Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add stream and stack examples.

  • Loading branch information...
commit 63831b5085c7f4b661b53ce207f3985fb5ddd5a2 1 parent 41a8452
@mbostock mbostock authored
View
37 _includes/Makefile
@@ -32,7 +32,13 @@ EX_FILES = \
../ex/flowers.json \
../ex/unemployment.json \
../ex/us-counties.json \
- ../ex/us-states.json
+ ../ex/us-states.json \
+ ../ex/stream.css \
+ ../ex/button.css \
+ ../ex/stack.css \
+ ../ex/stream.js \
+ ../ex/stream_layers.js \
+ ../ex/stack.js \
INCLUDE_FILES = \
chord.js \
@@ -40,7 +46,10 @@ INCLUDE_FILES = \
dji.js \
force.js \
splom.js \
- cross.js
+ cross.js \
+ stream.js \
+ stream_layers.js \
+ stack.js
.PHONY all: $(SRC_FILES) $(EX_FILES) $(INCLUDE_FILES)
@@ -128,3 +137,27 @@ $(SRC_FILES):
../ex/flowers.json:
@rm -rf $@
git cat-file blob master:examples/splom/flowers.json > $@
+
+../ex/stack.js stack.js:
+ @rm -rf $@
+ git cat-file blob master:examples/stream/stack.js > $@
+
+../ex/stream.js stream.js:
+ @rm -rf $@
+ git cat-file blob master:examples/stream/stream.js > $@
+
+../ex/stream_layers.js stream_layers.js:
+ @rm -rf $@
+ git cat-file blob master:examples/stream/stream_layers.js > $@
+
+../ex/stream.css:
+ @rm -rf $@
+ git cat-file blob master:examples/stream/stream.css > $@
+
+../ex/stack.css:
+ @rm -rf $@
+ git cat-file blob master:examples/stream/stack.css > $@
+
+../ex/button.css:
+ @rm -rf $@
+ git cat-file blob master:examples/stream/button.css > $@
View
119 _includes/stack.js
@@ -0,0 +1,119 @@
+var n = 4, // number of layers
+ m = 64, // number of samples per layer
+ data = d3.layout.stack()(stream_layers(n, m, .1)),
+ color = d3.interpolateRgb("#aad", "#556");
+
+var p = 20,
+ w = 960,
+ h = 500 - p,
+ mx = m,
+ my = d3.max(data, function(d) {
+ return d3.max(d, function(d) {
+ return d.y0 + d.y;
+ });
+ }),
+ mz = d3.max(data, function(d) {
+ return d3.max(d, function(d) {
+ return d.y;
+ });
+ }),
+ x = function(d) { return d.x * w / mx; },
+ y0 = function(d) { return h - d.y0 * h / my; },
+ y1 = function(d) { return h - (d.y + d.y0) * h / my; },
+ y2 = function(d) { return d.y * h / mz; }; // or `my` to not rescale
+
+var vis = d3.select("#chart")
+ .append("svg:svg")
+ .attr("width", w)
+ .attr("height", h + p);
+
+var layers = vis.selectAll("g.layer")
+ .data(data)
+ .enter().append("svg:g")
+ .attr("fill", function(d, i) { return color(i / (n - 1)); })
+ .attr("class", "layer");
+
+var bars = layers.selectAll("g.bar")
+ .data(function(d) { return d; })
+ .enter().append("svg:g")
+ .attr("class", "bar")
+ .attr("transform", function(d) { return "translate(" + x(d) + ",0)"; });
+
+bars.append("svg:rect")
+ .attr("width", x({x: .9}))
+ .attr("x", 0)
+ .attr("y", h)
+ .attr("height", 0)
+ .transition()
+ .delay(function(d, i) { return i * 10; })
+ .attr("y", y1)
+ .attr("height", function(d) { return y0(d) - y1(d); });
+
+var labels = vis.selectAll("text.label")
+ .data(data[0])
+ .enter().append("svg:text")
+ .attr("class", "label")
+ .attr("x", x)
+ .attr("y", h + 6)
+ .attr("dx", x({x: .45}))
+ .attr("dy", ".71em")
+ .attr("text-anchor", "middle")
+ .text(function(d, i) { return i; });
+
+vis.append("svg:line")
+ .attr("x1", 0)
+ .attr("x2", w - x({x: .1}))
+ .attr("y1", h)
+ .attr("y2", h);
+
+function transitionGroup() {
+ var group = d3.selectAll("#chart");
+
+ group.select("#group")
+ .attr("class", "first active");
+
+ group.select("#stack")
+ .attr("class", "last");
+
+ group.selectAll("g.layer rect")
+ .transition()
+ .duration(500)
+ .delay(function(d, i) { return (i % m) * 10; })
+ .attr("x", function(d, i) { return x({x: .9 * ~~(i / m) / n}); })
+ .attr("width", x({x: .9 / n}))
+ .each("end", transitionEnd);
+
+ function transitionEnd() {
+ d3.select(this)
+ .transition()
+ .duration(500)
+ .attr("y", function(d) { return h - y2(d); })
+ .attr("height", y2);
+ }
+}
+
+function transitionStack() {
+ var stack = d3.select("#chart");
+
+ stack.select("#group")
+ .attr("class", "first");
+
+ stack.select("#stack")
+ .attr("class", "last active");
+
+ stack.selectAll("g.layer rect")
+ .transition()
+ .duration(500)
+ .delay(function(d, i) { return (i % m) * 10; })
+ .attr("y", y1)
+ .attr("height", function(d) { return y0(d) - y1(d); })
+ .each("end", transitionEnd);
+
+ function transitionEnd() {
+ d3.select(this)
+ .transition()
+ .duration(500)
+ .attr("x", 0)
+ .attr("width", x({x: .9}));
+ }
+}
View
43 _includes/stream.js
@@ -0,0 +1,43 @@
+var n = 20, // number of layers
+ m = 200, // number of samples per layer
+ data0 = d3.layout.stack().offset("wiggle")(stream_layers(n, m)),
+ data1 = d3.layout.stack().offset("wiggle")(stream_layers(n, m)),
+ color = d3.interpolateRgb("#aad", "#556");
+
+var w = 960,
+ h = 500,
+ mx = m - 1,
+ my = d3.max(data0.concat(data1), function(d) {
+ return d3.max(d, function(d) {
+ return d.y0 + d.y;
+ });
+ });
+
+var area = d3.svg.area()
+ .x(function(d) { return d.x * w / mx; })
+ .y0(function(d) { return h - d.y0 * h / my; })
+ .y1(function(d) { return h - (d.y + d.y0) * h / my; });
+
+var vis = d3.select("#chart")
+ .append("svg:svg")
+ .attr("width", w)
+ .attr("height", h);
+
+vis.selectAll("path")
+ .data(data0)
+ .enter().append("svg:path")
+ .attr("fill", function() { return color(Math.random()); })
+ .attr("d", area);
+
+function transition() {
+ d3.selectAll("path")
+ .data(function() {
+ var d = data1;
+ data1 = data0;
+ return data0 = d;
+ })
+ .transition()
+ .delay(500)
+ .duration(2500)
+ .attr("d", area);
+}
View
33 _includes/stream_layers.js
@@ -0,0 +1,33 @@
+/* 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);
+ });
+}
+
+/* Another layer generator using gamma distributions. */
+function stream_waves(n, m) {
+ return d3.range(n).map(function(i) {
+ return d3.range(m).map(function(j) {
+ var x = 20 * j / m - i / 3;
+ return 2 * x * Math.exp(-.5 * x);
+ }).map(stream_index);
+ });
+}
+
+function stream_index(d, i) {
+ return {x: i, y: Math.max(0, d)};
+}
View
32 ex/button.css
@@ -0,0 +1,32 @@
+button {
+ font: 14px Helvetica Neue;
+ background: #222 url(http://bost.ocks.org/button-overlay.png) repeat-x;
+ 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;
+}
View
12 ex/stack.css
@@ -0,0 +1,12 @@
+#chart {
+ font: 10px sans-serif;
+}
+
+rect {
+ shape-rendering: crispEdges;
+}
+
+line {
+ stroke: black;
+ shape-rendering: crispEdges;
+}
View
119 ex/stack.js
@@ -0,0 +1,119 @@
+var n = 4, // number of layers
+ m = 64, // number of samples per layer
+ data = d3.layout.stack()(stream_layers(n, m, .1)),
+ color = d3.interpolateRgb("#aad", "#556");
+
+var p = 20,
+ w = 960,
+ h = 500 - p,
+ mx = m,
+ my = d3.max(data, function(d) {
+ return d3.max(d, function(d) {
+ return d.y0 + d.y;
+ });
+ }),
+ mz = d3.max(data, function(d) {
+ return d3.max(d, function(d) {
+ return d.y;
+ });
+ }),
+ x = function(d) { return d.x * w / mx; },
+ y0 = function(d) { return h - d.y0 * h / my; },
+ y1 = function(d) { return h - (d.y + d.y0) * h / my; },
+ y2 = function(d) { return d.y * h / mz; }; // or `my` to not rescale
+
+var vis = d3.select("#chart")
+ .append("svg:svg")
+ .attr("width", w)
+ .attr("height", h + p);
+
+var layers = vis.selectAll("g.layer")
+ .data(data)
+ .enter().append("svg:g")
+ .attr("fill", function(d, i) { return color(i / (n - 1)); })
+ .attr("class", "layer");
+
+var bars = layers.selectAll("g.bar")
+ .data(function(d) { return d; })
+ .enter().append("svg:g")
+ .attr("class", "bar")
+ .attr("transform", function(d) { return "translate(" + x(d) + ",0)"; });
+
+bars.append("svg:rect")
+ .attr("width", x({x: .9}))
+ .attr("x", 0)
+ .attr("y", h)
+ .attr("height", 0)
+ .transition()
+ .delay(function(d, i) { return i * 10; })
+ .attr("y", y1)
+ .attr("height", function(d) { return y0(d) - y1(d); });
+
+var labels = vis.selectAll("text.label")
+ .data(data[0])
+ .enter().append("svg:text")
+ .attr("class", "label")
+ .attr("x", x)
+ .attr("y", h + 6)
+ .attr("dx", x({x: .45}))
+ .attr("dy", ".71em")
+ .attr("text-anchor", "middle")
+ .text(function(d, i) { return i; });
+
+vis.append("svg:line")
+ .attr("x1", 0)
+ .attr("x2", w - x({x: .1}))
+ .attr("y1", h)
+ .attr("y2", h);
+
+function transitionGroup() {
+ var group = d3.selectAll("#chart");
+
+ group.select("#group")
+ .attr("class", "first active");
+
+ group.select("#stack")
+ .attr("class", "last");
+
+ group.selectAll("g.layer rect")
+ .transition()
+ .duration(500)
+ .delay(function(d, i) { return (i % m) * 10; })
+ .attr("x", function(d, i) { return x({x: .9 * ~~(i / m) / n}); })
+ .attr("width", x({x: .9 / n}))
+ .each("end", transitionEnd);
+
+ function transitionEnd() {
+ d3.select(this)
+ .transition()
+ .duration(500)
+ .attr("y", function(d) { return h - y2(d); })
+ .attr("height", y2);
+ }
+}
+
+function transitionStack() {
+ var stack = d3.select("#chart");
+
+ stack.select("#group")
+ .attr("class", "first");
+
+ stack.select("#stack")
+ .attr("class", "last active");
+
+ stack.selectAll("g.layer rect")
+ .transition()
+ .duration(500)
+ .delay(function(d, i) { return (i % m) * 10; })
+ .attr("y", y1)
+ .attr("height", function(d) { return y0(d) - y1(d); })
+ .each("end", transitionEnd);
+
+ function transitionEnd() {
+ d3.select(this)
+ .transition()
+ .duration(500)
+ .attr("x", 0)
+ .attr("width", x({x: .9}));
+ }
+}
View
32 ex/stack.markdown
@@ -0,0 +1,32 @@
+---
+layout: ex
+title: Stacked Bars
+---
+
+# Stacked Bars
+
+<div class="gallery" id="chart">
+ <button id="group" class="first" onclick="transitionGroup()">
+ Group
+ </button
+ ><button id="stack" class="last active" onclick="transitionStack()">
+ Stack
+ </button><br>
+</div>
+
+<link type="text/css" rel="stylesheet" href="stack.css"/>
+<link type="text/css" rel="stylesheet" href="button.css"/>
+<script type="text/javascript" src="../d3.js"> </script>
+<script type="text/javascript" src="../d3.layout.js"> </script>
+<script type="text/javascript" src="stream_layers.js"> </script>
+<script type="text/javascript" src="stack.js"> </script>
+
+### Source Code
+
+{% highlight js linenos %}
+{% include stack.js %}
+{% endhighlight %}
+
+{% highlight js linenos %}
+{% include stream_layers.js %}
+{% endhighlight %}
View
3  ex/stream.css
@@ -0,0 +1,3 @@
+#chart {
+ font: 10px sans-serif;
+}
View
43 ex/stream.js
@@ -0,0 +1,43 @@
+var n = 20, // number of layers
+ m = 200, // number of samples per layer
+ data0 = d3.layout.stack().offset("wiggle")(stream_layers(n, m)),
+ data1 = d3.layout.stack().offset("wiggle")(stream_layers(n, m)),
+ color = d3.interpolateRgb("#aad", "#556");
+
+var w = 960,
+ h = 500,
+ mx = m - 1,
+ my = d3.max(data0.concat(data1), function(d) {
+ return d3.max(d, function(d) {
+ return d.y0 + d.y;
+ });
+ });
+
+var area = d3.svg.area()
+ .x(function(d) { return d.x * w / mx; })
+ .y0(function(d) { return h - d.y0 * h / my; })
+ .y1(function(d) { return h - (d.y + d.y0) * h / my; });
+
+var vis = d3.select("#chart")
+ .append("svg:svg")
+ .attr("width", w)
+ .attr("height", h);
+
+vis.selectAll("path")
+ .data(data0)
+ .enter().append("svg:path")
+ .attr("fill", function() { return color(Math.random()); })
+ .attr("d", area);
+
+function transition() {
+ d3.selectAll("path")
+ .data(function() {
+ var d = data1;
+ data1 = data0;
+ return data0 = d;
+ })
+ .transition()
+ .delay(500)
+ .duration(2500)
+ .attr("d", area);
+}
View
29 ex/stream.markdown
@@ -0,0 +1,29 @@
+---
+layout: ex
+title: Streamgraph
+---
+
+# Streamgraph
+
+<div class="gallery" id="chart">
+ <button class="first last" onclick="transition()">
+ Update
+ </button><br>
+</div>
+
+<link type="text/css" rel="stylesheet" href="stream.css"/>
+<link type="text/css" rel="stylesheet" href="button.css"/>
+<script type="text/javascript" src="../d3.js"> </script>
+<script type="text/javascript" src="../d3.layout.js"> </script>
+<script type="text/javascript" src="stream_layers.js"> </script>
+<script type="text/javascript" src="stream.js"> </script>
+
+### Source Code
+
+{% highlight js linenos %}
+{% include stream.js %}
+{% endhighlight %}
+
+{% highlight js linenos %}
+{% include stream_layers.js %}
+{% endhighlight %}
View
33 ex/stream_layers.js
@@ -0,0 +1,33 @@
+/* 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);
+ });
+}
+
+/* Another layer generator using gamma distributions. */
+function stream_waves(n, m) {
+ return d3.range(n).map(function(i) {
+ return d3.range(m).map(function(j) {
+ var x = 20 * j / m - i / 3;
+ return 2 * x * Math.exp(-.5 * x);
+ }).map(stream_index);
+ });
+}
+
+function stream_index(d, i) {
+ return {x: i, y: Math.max(0, d)};
+}
View
BIN  stack.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  stream.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Please sign in to comment.
Something went wrong with that request. Please try again.