Skip to content

Instantly share code, notes, and snippets.

@espinielli
Last active February 14, 2017 12:04
Show Gist options
  • Save espinielli/950dd177406e91f97ff755c56343c2d3 to your computer and use it in GitHub Desktop.
Save espinielli/950dd177406e91f97ff755c56343c2d3 to your computer and use it in GitHub Desktop.
Streamgraph of ATFM delay causes
license: gpl-3.0

Plot the streamgraph of ATFM delay causes and print highlighted value under the cursor.

Mar-2014 - Jul-2016 Done:

TODO:

  • re-enable and re-work mouse hover
  • check data for NA on dates
  • x-axis ticks

forked from/inspired by biovisualize's block: Streamgraph extent under cursor

key value date
ap_capacity_atc 0.01 2014-03-01
ap_capacity_atc 0.01 2014-04-01
ap_capacity_atc 0.03 2014-05-01
ap_capacity_atc 0.03 2014-06-01
ap_capacity_atc 0.03 2014-07-01
ap_capacity_atc 0.03 2014-08-01
ap_capacity_atc 0.04 2014-09-01
ap_capacity_atc 0.06 2014-10-01
ap_capacity_atc 0.04 2014-11-01
ap_capacity_atc 0.02 2014-12-01
ap_capacity_atc 0.02 2015-01-01
ap_capacity_atc 0.03 2015-02-01
ap_capacity_atc 0.02 2015-03-01
ap_capacity_atc 0.01 2015-04-01
ap_capacity_atc 0.02 2015-05-01
ap_capacity_atc 0.03 2015-06-01
ap_capacity_atc 0.03 2015-07-01
ap_capacity_atc 0.02 2015-08-01
ap_capacity_atc 0.03 2015-09-01
ap_capacity_atc 0.01 2015-10-01
ap_capacity_atc 0 2015-11-01
ap_capacity_atc 0 2015-12-01
ap_capacity_atc 0.01 2016-01-01
ap_capacity_atc 0.01 2016-02-01
ap_capacity_atc 0.01 2016-03-01
ap_capacity_atc 0.01 2016-04-01
ap_capacity_atc 0.03 2016-05-01
ap_capacity_atc 0.05 2016-06-01
ap_capacity_atc 0.09 2016-07-01
ap_staffing_ATC 0 2014-03-01
ap_staffing_ATC 0 2014-04-01
ap_staffing_ATC 0.01 2014-05-01
ap_staffing_ATC 0.01 2014-06-01
ap_staffing_ATC 0.01 2014-07-01
ap_staffing_ATC 0.01 2014-08-01
ap_staffing_ATC 0.02 2014-09-01
ap_staffing_ATC 0.01 2014-10-01
ap_staffing_ATC 0.01 2014-11-01
ap_staffing_ATC 0.01 2014-12-01
ap_staffing_ATC 0 2015-01-01
ap_staffing_ATC 0.01 2015-02-01
ap_staffing_ATC 0 2015-03-01
ap_staffing_ATC 0 2015-04-01
ap_staffing_ATC 0 2015-05-01
ap_staffing_ATC 0 2015-06-01
ap_staffing_ATC 0 2015-07-01
ap_staffing_ATC 0.01 2015-08-01
ap_staffing_ATC 0 2015-09-01
ap_staffing_ATC 0.01 2015-10-01
ap_staffing_ATC 0 2015-11-01
ap_staffing_ATC 0 2015-12-01
ap_staffing_ATC 0 2016-01-01
ap_staffing_ATC 0.01 2016-02-01
ap_staffing_ATC 0.01 2016-03-01
ap_staffing_ATC 0.03 2016-04-01
ap_staffing_ATC 0.02 2016-05-01
ap_staffing_ATC 0.02 2016-06-01
ap_staffing_ATC 0.03 2016-07-01
ap_disruptions_ATC 0.01 2014-03-01
ap_disruptions_ATC 0 2014-04-01
ap_disruptions_ATC 0.02 2014-05-01
ap_disruptions_ATC 0.04 2014-06-01
ap_disruptions_ATC 0.03 2014-07-01
ap_disruptions_ATC 0 2014-08-01
ap_disruptions_ATC 0.01 2014-09-01
ap_disruptions_ATC 0.01 2014-10-01
ap_disruptions_ATC 0 2014-11-01
ap_disruptions_ATC 0.01 2014-12-01
ap_disruptions_ATC 0.02 2015-01-01
ap_disruptions_ATC 0.01 2015-02-01
ap_disruptions_ATC 0.01 2015-03-01
ap_disruptions_ATC 0.03 2015-04-01
ap_disruptions_ATC 0.01 2015-05-01
ap_disruptions_ATC 0.02 2015-06-01
ap_disruptions_ATC 0.01 2015-07-01
ap_disruptions_ATC 0.01 2015-08-01
ap_disruptions_ATC 0.01 2015-09-01
ap_disruptions_ATC 0.01 2015-10-01
ap_disruptions_ATC 0 2015-11-01
ap_disruptions_ATC 0 2015-12-01
ap_disruptions_ATC 0.02 2016-01-01
ap_disruptions_ATC 0.01 2016-02-01
ap_disruptions_ATC 0.04 2016-03-01
ap_disruptions_ATC 0.02 2016-04-01
ap_disruptions_ATC 0.02 2016-05-01
ap_disruptions_ATC 0.04 2016-06-01
ap_disruptions_ATC 0.01 2016-07-01
ap_weather 0.13 2014-03-01
ap_weather 0.23 2014-04-01
ap_weather 0.27 2014-05-01
ap_weather 0.21 2014-06-01
ap_weather 0.35 2014-07-01
ap_weather 0.32 2014-08-01
ap_weather 0.34 2014-09-01
ap_weather 0.32 2014-10-01
ap_weather 0.26 2014-11-01
ap_weather 0.44 2014-12-01
ap_weather 0.49 2015-01-01
ap_weather 0.39 2015-02-01
ap_weather 0.32 2015-03-01
ap_weather 0.18 2015-04-01
ap_weather 0.24 2015-05-01
ap_weather 0.25 2015-06-01
ap_weather 0.17 2015-07-01
ap_weather 0.22 2015-08-01
ap_weather 0.33 2015-09-01
ap_weather 0.28 2015-10-01
ap_weather 0.69 2015-11-01
ap_weather 0.51 2015-12-01
ap_weather 0.4 2016-01-01
ap_weather 0.37 2016-02-01
ap_weather 0.28 2016-03-01
ap_weather 0.12 2016-04-01
ap_weather 0.27 2016-05-01
ap_weather 0.46 2016-06-01
ap_weather 0.21 2016-07-01
ap_capacity_non_atc 0.04 2014-03-01
ap_capacity_non_atc 0.04 2014-04-01
ap_capacity_non_atc 0.07 2014-05-01
ap_capacity_non_atc 0.15 2014-06-01
ap_capacity_non_atc 0.19 2014-07-01
ap_capacity_non_atc 0.28 2014-08-01
ap_capacity_non_atc 0.15 2014-09-01
ap_capacity_non_atc 0.14 2014-10-01
ap_capacity_non_atc 0.08 2014-11-01
ap_capacity_non_atc 0.15 2014-12-01
ap_capacity_non_atc 0.14 2015-01-01
ap_capacity_non_atc 0.1 2015-02-01
ap_capacity_non_atc 0.12 2015-03-01
ap_capacity_non_atc 0.21 2015-04-01
ap_capacity_non_atc 0.31 2015-05-01
ap_capacity_non_atc 0.38 2015-06-01
ap_capacity_non_atc 0.64 2015-07-01
ap_capacity_non_atc 0.78 2015-08-01
ap_capacity_non_atc 0.53 2015-09-01
ap_capacity_non_atc 0.31 2015-10-01
ap_capacity_non_atc 0.28 2015-11-01
ap_capacity_non_atc 0.29 2015-12-01
ap_capacity_non_atc 0.3 2016-01-01
ap_capacity_non_atc 0.26 2016-02-01
ap_capacity_non_atc 0.3 2016-03-01
ap_capacity_non_atc 0.22 2016-04-01
ap_capacity_non_atc 0.34 2016-05-01
ap_capacity_non_atc 0.31 2016-06-01
ap_capacity_non_atc 0.56 2016-07-01
ap_disruptions_non_atc 0 2014-03-01
ap_disruptions_non_atc 0.01 2014-04-01
ap_disruptions_non_atc 0.01 2014-05-01
ap_disruptions_non_atc 0.03 2014-06-01
ap_disruptions_non_atc 0.01 2014-07-01
ap_disruptions_non_atc 0.02 2014-08-01
ap_disruptions_non_atc 0.01 2014-09-01
ap_disruptions_non_atc 0.01 2014-10-01
ap_disruptions_non_atc 0.01 2014-11-01
ap_disruptions_non_atc 0.02 2014-12-01
ap_disruptions_non_atc 0.01 2015-01-01
ap_disruptions_non_atc 0.02 2015-02-01
ap_disruptions_non_atc 0.02 2015-03-01
ap_disruptions_non_atc 0.03 2015-04-01
ap_disruptions_non_atc 0.07 2015-05-01
ap_disruptions_non_atc 0.07 2015-06-01
ap_disruptions_non_atc 0.06 2015-07-01
ap_disruptions_non_atc 0.03 2015-08-01
ap_disruptions_non_atc 0.01 2015-09-01
ap_disruptions_non_atc 0 2015-10-01
ap_disruptions_non_atc 0.01 2015-11-01
ap_disruptions_non_atc 0.01 2015-12-01
ap_disruptions_non_atc 0 2016-01-01
ap_disruptions_non_atc 0.01 2016-02-01
ap_disruptions_non_atc 0.01 2016-03-01
ap_disruptions_non_atc 0.02 2016-04-01
ap_disruptions_non_atc 0.01 2016-05-01
ap_disruptions_non_atc 0.02 2016-06-01
ap_disruptions_non_atc 0.01 2016-07-01
ap_events_non_atc 0 2014-03-01
ap_events_non_atc 0.01 2014-04-01
ap_events_non_atc 0.01 2014-05-01
ap_events_non_atc 0 2014-06-01
ap_events_non_atc 0.01 2014-07-01
ap_events_non_atc 0.02 2014-08-01
ap_events_non_atc 0 2014-09-01
ap_events_non_atc 0 2014-10-01
ap_events_non_atc 0.03 2014-11-01
ap_events_non_atc 0 2014-12-01
ap_events_non_atc 0 2015-01-01
ap_events_non_atc 0.01 2015-02-01
ap_events_non_atc 0.05 2015-03-01
ap_events_non_atc 0.04 2015-04-01
ap_events_non_atc 0.06 2015-05-01
ap_events_non_atc 0.01 2015-06-01
ap_events_non_atc 0.01 2015-07-01
ap_events_non_atc 0 2015-08-01
ap_events_non_atc 0 2015-09-01
ap_events_non_atc 0 2015-10-01
ap_events_non_atc 0.01 2015-11-01
ap_events_non_atc 0.02 2015-12-01
ap_events_non_atc 0 2016-01-01
ap_events_non_atc 0.01 2016-02-01
ap_events_non_atc 0 2016-03-01
ap_events_non_atc 0 2016-04-01
ap_events_non_atc 0.01 2016-05-01
ap_events_non_atc 0.01 2016-06-01
ap_events_non_atc 0.01 2016-07-01
<!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: grey;
stroke-width: 2px;
shape-rendering: crispEdges;
}
.grid .tick {
stroke: grey;
stroke-opacity: 0.2;
shape-rendering: crispEdges;
}
.tooltip { background-color:rgba(68,136,187,0.5);;
margin: 10px;
height: 50px;
width: 150px;
padding-left: 10px;
padding-top: 10px;
-webkit-border-radius:10px;
-moz-border-radius:10px;
border-radius:10px;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<!-- <script type="text/javascript" src="tooltip.js"></script> -->
<script src="http://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
<div class="chart">
</div>
<script>
// "blue"
colorrange = ["#045A8D", "#2B8CBE", "#74A9CF", "#A6BDDB", "#D0D1E6", "#F1EEF6"];
// "pink"
//colorrange = ["#980043", "#DD1C77", "#DF65B0", "#C994C7", "#D4B9DA", "#F1EEF6"];
// "orange"
//colorrange = ["#B30000", "#E34A33", "#FC8D59", "#FDBB84", "#FDD49E", "#FEF0D9"];
chart("data.csv", colorrange);
var datearray = [];
var colorrange = [];
function chart(csvpath, colorrange) {
strokecolor = colorrange[0];
var format = d3.time.format("%Y-%m-%d");
var margin = {top: 20, right: 40, bottom: 40, left: 30};
var width = document.body.clientWidth - margin.left - margin.right;
var height = 400 - margin.top - margin.bottom;
// function for the x grid lines
function make_x_axis() {
return d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(d3.time.months)
}
var tooltip = d3.select("body")
.append("div")
.attr("class", "remove")
.style("position", "absolute")
.style("z-index", "20")
.style("visibility", "hidden")
.style("top", "320px")
.style("left", "45px");
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height - 10, 0]);
var z = d3.scale.ordinal()
.range(colorrange);
var xAxis = make_x_axis();
var yAxis = d3.svg.axis()
.scale(y);
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));
var xdom = d3.extent(data, function(d) { return d.date; });
x.domain(xdom);
y.domain([0, d3.max(data, function(d) { return d.y0 + d.y; })]);
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); });
// Draw the x Grid lines
svg.append("g")
.attr("class", "grid")
.attr("transform", "translate(0," + height + ")")
.call(make_x_axis()
.tickSize(-height, 0, 0)
.tickFormat("")
);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text") // rotate ticks labels
.attr("y", 0)
.attr("x", 9)
.attr("dy", ".35em")
.attr("transform", "rotate(40)")
.style("text-anchor", "start");
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"));
// the cursor for the tooltip
var axisExtentLine = svg.append("line")
.attr({"class": "extent",
"stroke-width": 5,
"stroke-opacity": 0.8,
"stroke": "red",
"pointer-events": "none"
});
// the cursor in the stream under the mouse
var cursorExtentLine = svg.append("line")
.attr({"class": "extent",
"stroke-width": 3,
"stroke-opacity": 0.8,
"stroke": "white",
"pointer-events": "none"
});
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;
})
.attr("stroke", function(d, j) {
return j != i ? "none" : "black";
})
})
/* .call(d3.helper.tooltip(
function(d, i){
console.log(d);
console.log(i);
console.log(d.values);
return "<b>"+d + "</b><br/>pop: "+d;
}
)) */
.on("mousemove", function(d, i) {
mouse = d3.mouse(this);
// get the date at mouse position
var dateATx = x.invert(mouse[0]);
// make it the fisrt of the month
dateATx = new Date(dateATx.getFullYear(), dateATx.getMonth(), 1);
// get the entry in d.values that matches the first of the month under the mouse
var entry = _.find(d.values, function(o) {return o.date.getTime() == dateATx.getTime();});
pro = entry.value || 0;
var posY = entry.y0;
var posX = x(entry.date);
axisExtentLine.attr({x1: 0, y1: y(pro),
x2: 0, y2: height -10 });
cursorExtentLine.attr({x1: posX, y1: y(pro) - (height - y(posY) - 10),
x2: posX, y2: height - (height - y(posY)) });
d3.select(this)
.classed("hover", true)
.attr("stroke", strokecolor)
.attr("stroke-width", "1px"),
tooltip.html( "<p>" + d.key + "<br>" + pro + "</p>" )
.style("visibility", "visible");
})
// .on("mouseout", fade(1))
.on("mouseout", function(d, i) {
svg.selectAll(".layer")
.transition()
.duration(250)
.attr("opacity", "1");
d3.select(this)
.classed("hover", false)
.attr("stroke-width", "0px");
tooltip.html( "<p>" + d.key + "<br>" + pro + "</p>" )
.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", "340px")
.style("top", "20px")
.style("bottom", "30px")
.style("left", "0px")
.style("background", "#f00");
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")});
});
}
function fade(opacity) {
return function(g, i) {
streamgraph.layers()
.filter(function(h, j) {
return j != i;
})
.transition(1000)
.style("opacity", opacity);
}
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment