Skip to content

Instantly share code, notes, and snippets.

@kielni
Forked from WillTurman/Readme.md
Last active April 10, 2018 17:29
Show Gist options
  • Save kielni/8239732 to your computer and use it in GitHub Desktop.
Save kielni/8239732 to your computer and use it in GitHub Desktop.

D3 Streamgraph Example

Series Hover

The series hover interactivity uses the technique from lgrammel seen here: http://bl.ocks.org/1963983

Data Tooltip

It isn't necessarily a tooltip, but data is displayed by inverting the x-axis value into a date, and mapping the date to the corresponding data value for the series.

If there is a simpler way to do this, I'd love to see an example, as I couldn't find any other examples of this out there.

Vertical Line Tooltip

I think the vertical line adds a little bit of visual orientation to the streamgraph.

Colors

I left a few alternate color ranges in the code (which are essentially taken straight from colorbrewer), in case orange doesn't sit well.

key value date
AR 0.1 01/08/13
AR 0.15 01/09/13
AR 0.35 01/10/13
AR 0.38 01/11/13
AR 0.22 01/12/13
AR 0.16 01/13/13
AR 0.07 01/14/13
AR 0.02 01/15/13
AR 0.17 01/16/13
AR 0.33 01/17/13
AR 0.4 01/18/13
AR 0.32 01/19/13
AR 0.26 01/20/13
AR 0.35 01/21/13
AR 0.4 01/22/13
AR 0.32 01/23/13
AR 0.26 01/24/13
AR 0.22 01/25/13
AR 0.16 01/26/13
AR 0.22 01/27/13
AR 0.1 01/28/13
DJ 0.35 01/08/13
DJ 0.36 01/09/13
DJ 0.37 01/10/13
DJ 0.22 01/11/13
DJ 0.24 01/12/13
DJ 0.26 01/13/13
DJ 0.34 01/14/13
DJ 0.21 01/15/13
DJ 0.18 01/16/13
DJ 0.45 01/17/13
DJ 0.32 01/18/13
DJ 0.35 01/19/13
DJ 0.3 01/20/13
DJ 0.28 01/21/13
DJ 0.27 01/22/13
DJ 0.26 01/23/13
DJ 0.15 01/24/13
DJ 0.3 01/25/13
DJ 0.35 01/26/13
DJ 0.42 01/27/13
DJ 0.42 01/28/13
MS 0.21 01/08/13
MS 0.25 01/09/13
MS 0.27 01/10/13
MS 0.23 01/11/13
MS 0.24 01/12/13
MS 0.21 01/13/13
MS 0.35 01/14/13
MS 0.39 01/15/13
MS 0.4 01/16/13
MS 0.36 01/17/13
MS 0.33 01/18/13
MS 0.43 01/19/13
MS 0.4 01/20/13
MS 0.34 01/21/13
MS 0.28 01/22/13
MS 0.26 01/23/13
MS 0.37 01/24/13
MS 0.41 01/25/13
MS 0.46 01/26/13
MS 0.47 01/27/13
MS 0.41 01/28/13
RC 0.1 01/08/13
RC 0.15 01/09/13
RC 0.35 01/10/13
RC 0.38 01/11/13
RC 0.22 01/12/13
RC 0.16 01/13/13
RC 0.07 01/14/13
RC 0.02 01/15/13
RC 0.17 01/16/13
RC 0.33 01/17/13
RC 0.4 01/18/13
RC 0.32 01/19/13
RC 0.26 01/20/13
RC 0.35 01/21/13
RC 0.4 01/22/13
RC 0.32 01/23/13
RC 0.26 01/24/13
RC 0.22 01/25/13
RC 0.16 01/26/13
RC 0.22 01/27/13
RC 0.1 01/28/13
CG 0.1 01/08/13
CG 0.15 01/09/13
CG 0.35 01/10/13
CG 0.38 01/11/13
CG 0.22 01/12/13
CG 0.16 01/13/13
CG 0.07 01/14/13
CG 0.02 01/15/13
CG 0.17 01/16/13
CG 0.33 01/17/13
CG 0.4 01/18/13
CG 0.32 01/19/13
CG 0.26 01/20/13
CG 0.35 01/21/13
CG 0.4 01/22/13
CG 0.32 01/23/13
CG 0.26 01/24/13
CG 0.22 01/25/13
CG 0.16 01/26/13
CG 0.22 01/27/13
CG 0.1 01/28/13
RI 0.1 01/08/13
RI 0.15 01/09/13
RI 0.35 01/10/13
RI 0.38 01/11/13
RI 0.22 01/12/13
RI 0.16 01/13/13
RI 0.07 01/14/13
RI 0.02 01/15/13
RI 0.17 01/16/13
RI 0.33 01/17/13
RI 0.4 01/18/13
RI 0.32 01/19/13
RI 0.26 01/20/13
RI 0.35 01/21/13
RI 0.4 01/22/13
RI 0.32 01/23/13
RI 0.26 01/24/13
RI 0.22 01/25/13
RI 0.16 01/26/13
RI 0.22 01/27/13
RI 0.1 01/28/13
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.chart {
background: #fff;
}
p {
font: 12px helvetica;
}
.axis path, .axis line {
fill: none;
stroke: #000;
stroke-width: 2px;
shape-rendering: crispEdges;
}
button {
position: absolute;
right: 50px;
top: 10px;
}
</style>
<body>
<script src="http://d3js.org/d3.v2.js"></script>
<div class="chart">
</div>
<script>
chart("data.csv", "orange");
var datearray = [];
var colorrange = [];
function chart(csvpath, color) {
if (color == "blue") {
colorrange = ["#045A8D", "#2B8CBE", "#74A9CF", "#A6BDDB", "#D0D1E6", "#F1EEF6"];
}
else if (color == "pink") {
colorrange = ["#980043", "#DD1C77", "#DF65B0", "#C994C7", "#D4B9DA", "#F1EEF6"];
}
else if (color == "orange") {
colorrange = ["#B30000", "#E34A33", "#FC8D59", "#FDBB84", "#FDD49E", "#FEF0D9"];
}
strokecolor = colorrange[0];
var format = d3.time.format("%m/%d/%y");
var margin = {top: 20, right: 40, bottom: 30, left: 30};
var width = document.body.clientWidth - margin.left - margin.right;
var height = 400 - margin.top - margin.bottom;
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height-10, 0]);
var ySymmetric = d3.scale.linear()
.range([height-10, 0]);
var z = d3.scale.ordinal()
.range(colorrange);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(d3.time.weeks);
var yAxis = d3.svg.axis()
.tickFormat(function(d) { return (d<0) ? -1*d : d; })
.scale(ySymmetric);
var yAxisr = d3.svg.axis()
.tickFormat(function(d) { return (d<0) ? -1*d : d; })
.scale(ySymmetric);
var stack = d3.layout.stack()
.offset("silhouette")
.values(function(d) { return d.values; })
.x(function(d) { return d.date; })
.y(function(d) { return d.value; });
var nest = d3.nest()
.key(function(d) { return d.key; });
var area = d3.svg.area()
.interpolate("cardinal")
.x(function(d) { return x(d.date); })
.y0(function(d) { return y(d.y0); })
.y1(function(d) { return y(d.y0 + d.y); });
var svg = d3.select(".chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var graph = d3.csv(csvpath, function(data) {
data.forEach(function(d) {
d.date = format.parse(d.date);
d.value = +d.value;
});
var layers = stack(nest.entries(data));
x.domain(d3.extent(data, function(d) { return d.date; }));
var ymax = d3.max(data, function(d) { return d.y0 + d.y; });
y.domain([0, ymax]);
ySymmetric.domain([-ymax/2, ymax/2]);
svg.selectAll(".layer")
.data(layers)
.enter().append("path")
.attr("class", "layer")
.attr("d", function(d) { return area(d.values); })
.style("fill", function(d, i) { return z(i); });
var tooltip = svg.append("g")
.attr("class", "tooltip");
tooltip.append("rect")
.attr("height", 20)
.style("fill", "#fff")
.style("opacity", 0.5);
tooltip.append("text")
.attr("class", "tooltip-text")
.attr("font-size", "10px")
.text("");
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + width + ", 0)")
.call(yAxis.orient("right"));
svg.append("g")
.attr("class", "y axis")
.call(yAxis.orient("left"));
svg.selectAll(".layer")
.attr("opacity", 1)
.on("mouseover", function(d, i) {
svg.selectAll(".layer").transition()
.duration(250)
.attr("opacity", function(d, j) {
return j != i ? 0.6 : 1;
})})
.on("mousemove", function(d, i) {
mousex = d3.mouse(this)[0];
mousey = d3.mouse(this)[1];
var ix = x.invert(mousex);
ix.setHours(0,0,0,0);
var ixTime = ix.getTime();
var selected = null;
for (var i = 0; i < d.values.length; i++) {
if ((d.values[i].date.getTime() - ixTime) == 0) {
selected = d.values[i];
break;
}
}
if (selected != null) {
d3.select(".tooltip").style("visibility", "visible");
var ypos = mousey + ((mousey > height/2) ? -10 : 20);
var mm = selected.date.getMonth()+1;
if (mm < 10) mm = "0"+mm;
var dd = selected.date.getDate();
if (dd < 10) dd = "0"+dd;
tooltip.select("text")
.attr("y", Math.round(ypos))
.text(mm+"/"+dd+" "+selected.key+" "+selected.value);
var textWidth = tooltip.select("text").node().getComputedTextLength();
var xpos, rxpos;
if (mousex > width/2) {
xpos = Math.round(mousex-textWidth-10);
rxpos = xpos;
} else {
xpos = Math.round(mousex+10);
rxpos = xpos-5;
}
tooltip.select("text")
.attr("x", xpos);
tooltip.select("rect")
.attr("width", textWidth+10)
.attr("x", rxpos)
.attr("y", Math.round(ypos-15));
}
})
.on("mouseout", function(d, i) {
svg.selectAll(".layer")
.transition()
.duration(250)
.attr("opacity", "1");
tooltip.style("visibility", "hidden");
})
var vertical = d3.select(".chart")
.append("div")
.attr("class", "remove")
.style("position", "absolute")
.style("z-index", "19")
.style("width", "1px")
.style("height", "380px")
.style("top", "10px")
.style("bottom", "30px")
.style("left", "0px")
.style("background", "#fff");
d3.select(".chart")
.on("mousemove", function(){
mousex = d3.mouse(this);
mousex = mousex[0] + 5;
vertical.style("left", mousex + "px" )})
.on("mouseover", function(){
mousex = d3.mouse(this);
mousex = mousex[0] + 5;
vertical.style("left", mousex + "px")});
});
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment