D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
madMatchstick
Full window
Github gist
Cox -Time Series Regression - Out 6 months
Built with
blockbuilder.org
<!DOCTYPE html> <meta charset="utf-8"> <style> /* set the CSS */ body { font: 12px Arial;} .upline, .downline { stroke-width: 2; fill: none; } .upline { stroke: blue; } .downline { stroke: red; } .axis path, .axis line { fill: none; stroke: grey; stroke-width: 1; shape-rendering: crispEdges; } .tick line {stroke: rgba(0, 0, 0, 0.1);stroke-dasharray:2;} .tick text {font-size: .9em} .tooltip { position: absolute; width: 75px; height: 24px; padding: 2px; background: white; pointer-events: none; } </style> <body> <!-- load the d3.js library --> <script src="https://d3js.org/d3.v4.min.js"></script> <script> var data = [{"month":"06-May-18","downstream_utilization_pct":42.2,"upstream_utilization_pct":94.1},{"month":"29-Apr-18","downstream_utilization_pct":44.9,"upstream_utilization_pct":84.9},{"month":"22-Apr-18","downstream_utilization_pct":44.9,"upstream_utilization_pct":74},{"month":"15-Apr-18","downstream_utilization_pct":45.8,"upstream_utilization_pct":76.8},{"month":"08-Apr-18","downstream_utilization_pct":45.9,"upstream_utilization_pct":null},{"month":"01-Apr-18","downstream_utilization_pct":45.1,"upstream_utilization_pct":73.3},{"month":"25-Mar-18","downstream_utilization_pct":44.8,"upstream_utilization_pct":77.4},{"month":"18-Mar-18","downstream_utilization_pct":null,"upstream_utilization_pct":84.1},{"month":"11-Mar-18","downstream_utilization_pct":null,"upstream_utilization_pct":70.8},{"month":"04-Mar-18","downstream_utilization_pct":null,"upstream_utilization_pct":77},{"month":"25-Feb-18","downstream_utilization_pct":null,"upstream_utilization_pct":84.2},{"month":"18-Feb-18","downstream_utilization_pct":null,"upstream_utilization_pct":77},{"month":"11-Feb-18","downstream_utilization_pct":null,"upstream_utilization_pct":81.3},{"month":"04-Feb-18","downstream_utilization_pct":null,"upstream_utilization_pct":79},{"month":"28-Jan-18","downstream_utilization_pct":null,"upstream_utilization_pct":74.6},{"month":"21-Jan-18","downstream_utilization_pct":null,"upstream_utilization_pct":75.5},{"month":"14-Jan-18","downstream_utilization_pct":null,"upstream_utilization_pct":67.4},{"month":"07-Jan-18","downstream_utilization_pct":null,"upstream_utilization_pct":69.3},{"month":"31-Dec-17","downstream_utilization_pct":null,"upstream_utilization_pct":67.9},{"month":"24-Dec-17","downstream_utilization_pct":null,"upstream_utilization_pct":76.8},{"month":"17-Dec-17","downstream_utilization_pct":null,"upstream_utilization_pct":70.5},{"month":"10-Dec-17","downstream_utilization_pct":null,"upstream_utilization_pct":51.8},{"month":"03-Dec-17","downstream_utilization_pct":null,"upstream_utilization_pct":69.6},{"month":"26-Nov-17","downstream_utilization_pct":null,"upstream_utilization_pct":63.6},{"month":"19-Nov-17","downstream_utilization_pct":null,"upstream_utilization_pct":72.6},{"month":"12-Nov-17","downstream_utilization_pct":42.6,"upstream_utilization_pct":60.1},{"month":"05-Nov-17","downstream_utilization_pct":42.4,"upstream_utilization_pct":65.9}]; // Set the dimensions of the canvas / graph var margin = {top: 30, right: 20, bottom: 30, left: 50}, width = 700 - margin.left - margin.right, height = 400 - margin.top - margin.bottom; // Parse the date / time var parseDate = d3.timeParse("%d-%b-%y"); var formatDate = d3.timeFormat("%d-%b-%y"); // Set the ranges var x = d3.scaleTime().range([0, width]); var y = d3.scaleLinear().range([height, 0]); // Define the line var upline = d3.line() .x(function(d) { return x(d.month); }) .y(function(d) { return y(d.upstream_utilization_pct); }); var downline = d3.line() .x(function(d) { return x(d.month); }) .y(function(d) { return y(d.downstream_utilization_pct); }); // Define the div for the tooltip var div = d3.select("body").append("div") .attr("class", "tooltip") .style("opacity", 0); // Adds the svg canvas var svg = d3.select("body") .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 + ")"); // Get the data var now = new Date; var filterData = data.filter(function(i) {return (parseDate(i.month) >= d3.timeWeek.offset(d3.timeWeek.floor(now), -26))}); console.log(data, filterData); filterData.forEach(function(d) { d.month = parseDate(d.month); d.upstream_utilization_pct = +d.upstream_utilization_pct; d.downstream_utilization_pct = +d.downstream_utilization_pct; }); // Scale the range of the data x.domain([d3.timeWeek.offset(d3.timeWeek.floor(now), -26),d3.timeWeek.offset(d3.timeWeek.floor(now), 26)]); y.domain([0, 100]); var filterDataDown = []; for (i in filterData){ if (filterData[i].downstream_utilization_pct != 0) { filterDataDown[i] = filterData[i]; } }; var filterDataUp = []; for (i in filterData){ if (filterData[i].upstream_utilization_pct != 0) { filterDataUp[i] = filterData[i]; } }; svg.append("path") .data([filterDataUp]) .attr("class", "upline") .attr("d", upline); svg.append("path") .data([filterDataDown]) .attr("class", "downline") .attr("d", downline); svg.selectAll(".trend") .data(data) .attr("stroke", function(d) { return z0(d.con); }) svg.selectAll(".dot") .data(filterData) .enter().append("circle") .attr("class", "dot") .attr("r", 3.5) .attr("cx", function(d) { return x(d.month); }) .attr("cy", function(d) { return y(d.upstream_utilization_pct); }) .style("fill-opacity", .01) .style("stroke-opacity", .01) .on("mouseover", function(d) { div.transition() .duration(200) .style("opacity", .9); div.html(formatDate(d.month) + "<br/><div style='color: blue;font-weight:bold'>" + d.upstream_utilization_pct + "</div>") .style("left", (d3.event.pageX + 10) + "px") .style("top", (d3.event.pageY - 30) + "px"); }) .on("mouseout", function(d) { div.transition() .duration(500) .style("opacity", 0); }); svg.selectAll(".dot2") .data(filterData) .enter().append("circle") .attr("class", "dot") .attr("r", 3.5) .attr("cx", function(d) { return x(d.month); }) .attr("cy", function(d) { return y(d.downstream_utilization_pct); }) .style("fill-opacity", .01) .style("stroke-opacity", .01) .on("mouseover", function(d) { var matrix = this.getScreenCTM() .translate(+ this.getAttribute("cx"), + this.getAttribute("cy")); div.transition() .duration(200) .style("opacity", .9); div.html(formatDate(d.month) + "<br/><div style='color: red;font-weight:bold'>" + d.downstream_utilization_pct + "</div>") .style("left", (window.pageXOffset + matrix.e + 15) + "px") .style("top", (window.pageYOffset + matrix.f - 30) + "px") // .style("left", (d3.event.pageX + 10) + "px") // .style("top", (d3.event.pageY - 30) + "px"); }) .on("mouseout", function(d) { div.transition() .duration(500) .style("opacity", 0); }); // Add the X Axis svg.append("g") .attr("class", "axis") .attr("transform", "translate(0," + height + ")") .call(d3.axisBottom(x).tickSizeInner(-height).tickPadding(5).tickSizeOuter(0).ticks(52) .tickFormat(function(d, i){return i;})) // text label for the x axis svg.append("text") .attr("transform", "translate(" + (width/2) + " ," + (height + margin.top) + ")") .style("text-anchor", "middle") .text("Week"); // Add the Y Axis svg.append("g") .attr("class", "axis") .call(d3.axisLeft(y).tickSizeInner(-width).ticks(10).tickPadding(5).tickSizeOuter(0)); // text label for the y axis svg.append("text") .attr("transform", "rotate(-90)") .attr("y", 0 - (margin.left / 1.25)) .attr("x",0 - (height / 2)) .attr("dy", "1em") .style("text-anchor", "middle") .text("95th Percentile"); // get the x and y values for least squares var xLabels = filterData.map(function (d) { return d['month']; }); console.log(xLabels); var yFilterUp = filterData.filter(function(d) { return d.upstream_utilization_pct > 0; }); var xSeriesUp = d3.range(1, yFilterUp.length + 1); var ySeriesUp = yFilterUp.map(function(d) { return d.upstream_utilization_pct; }); var yFilterDown = filterData.filter(function(d) { return d.downstream_utilization_pct > 0; }); var xSeriesDown = d3.range(1, yFilterDown.length + 1); var ySeriesDown = yFilterDown.map(function(d) { return d.downstream_utilization_pct; }); console.log(xSeriesUp, ySeriesUp); var leastSquaresCoeffUp = leastSquares(xSeriesUp, ySeriesUp); // apply the reults of the least squares regression var x1 = xLabels[0]; var y1 = leastSquaresCoeffUp[0] + leastSquaresCoeffUp[1]; var x2 = xLabels[xLabels.length - 1]; var y2 = leastSquaresCoeffUp[0] * xSeriesUp.length + leastSquaresCoeffUp[1]; var trendDataUp = [[x1,y1,x2,y2]]; console.log(trendDataUp); var trendlineUp = svg.selectAll(".trendlineUp") .data(trendDataUp); trendlineUp.enter() .append("line") .attr("class", "trendlineUp") .attr("x1", function(d) { return x(d3.timeWeek.offset(d3.timeWeek.floor(now), 26)); }) .attr("y1", function(d) { return y(d[1]+(d[1]-d[3])); }) .attr("x2", function(d) { return x(d[2]); }) .attr("y2", function(d) { return y(d[3]); }) .attr("stroke", "steelblue") .attr("stroke-width", 1); var leastSquaresCoeffDown = leastSquares(xSeriesDown, ySeriesDown); // apply the results of the least squares regression var x1 = xLabels[0]; var y1 = leastSquaresCoeffDown[0] + leastSquaresCoeffDown[1]; var x2 = xLabels[xLabels.length - 1]; var y2 = leastSquaresCoeffDown[0] * xSeriesDown.length + leastSquaresCoeffDown[1]; var trendDataDown = [[x1,y1,x2,y2]]; console.log(trendDataDown); var trendlineDown = svg.selectAll(".trendlineDown") .data(trendDataDown); trendlineDown.enter() .append("line") .attr("class", "trendline") .attr("x1", function(d) { return x(d3.timeWeek.offset(d3.timeWeek.floor(now), 26)); }) .attr("y1", function(d) { return y(d[1]+(d[1]-d[3])); }) .attr("x2", function(d) { return x(d[2]); }) .attr("y2", function(d) { return y(d[3]); }) .attr("stroke", "orange") .attr("stroke-width", 1); // returns slope, intercept and r-square of the line function leastSquares(xSeries, ySeries) { var reduceSumFunc = function(prev, cur) { return prev + cur; }; var nullValCounter = 0 for (i in ySeries) { if (i == 0){ nullValCounter += 1 } } console.log(ySeries, "nullvals = " + nullValCounter); var xBar = xSeries.reduce(reduceSumFunc) * 1.0 / xSeries.length; var yBar = ySeries.reduce(reduceSumFunc) * 1.0 / ySeries.length; var ssXX = xSeries.map(function(d) { return Math.pow(d - xBar, 2); }) .reduce(reduceSumFunc); var ssYY = ySeries.map(function(d) { return Math.pow(d - yBar, 2); }) .reduce(reduceSumFunc); var ssXY = xSeries.map(function(d, i) { return (d - xBar) * (ySeries[i] - yBar); }) .reduce(reduceSumFunc); var slope = ssXY / ssXX; var intercept = yBar - (xBar * slope); var rSquare = Math.pow(ssXY, 2) / (ssXX * ssYY); return [slope, intercept, rSquare]; } svg.append("text") .attr("y", -20) .attr("x", 25) .attr("font-size", 10) .attr("font-weight", "bold") .attr("fill", "blue") .style("text-anchor", "start") .text("Upstream Utilization"); svg.append("circle") .attr("cy", -24) .attr("cx", 15) .attr("fill", "blue") .attr("r", 4); svg.append("text") .attr("y", -5) .attr("x", 25) .attr("font-size", 10) .attr("font-weight", "bold") .attr("fill", "steelblue") .style("text-anchor", "start") .text("Trend"); svg.append("circle") .attr("cy", -9) .attr("cx", 15) .attr("fill", "steelblue") .attr("r", 4); svg.append("text") .attr("y", -20) .attr("x", 200) .attr("font-size", 10) .attr("font-weight", "bold") .attr("fill", "red") .style("text-anchor", "start") .text("Downstream Utilization"); svg.append("circle") .attr("cy", -24) .attr("cx", 190) .attr("fill", "red") .attr("r", 4); svg.append("text") .attr("y", -5) .attr("x", 200) .attr("font-size", 10) .attr("font-weight", "bold") .attr("fill", "orange") .style("text-anchor", "start") .text("Trend"); svg.append("circle") .attr("cy", -9) .attr("cx", 190) .attr("fill", "orange") .attr("r", 4); </script> </body>
https://d3js.org/d3.v4.min.js