我正在建立折线图以进行简单的预测,但是最后一个数据点显示的日期不正确时,我遇到了问题。
我的代码:https://jsfiddle.net/5pztkwra/- 样本图片:Burn-up forecasting
即蓝线和橙色线的最后一点应显示为20年7月6日,而显示为20年7月11日。
在第170行中,我向最后一个日期添加了5天,以使用endDate.setDate(endDate.getDate() + 5);
来扩展X轴的长度
试图在图表中添加额外的空间,以使虚线“趋势”线和蓝线相遇。
这另外5天似乎是造成此问题的原因。有什么想法可以解决吗?
谢谢
答案 0 :(得分:0)
以某种方式setDate
函数更改数据元素,以便最后一个数据的日期为11-Jul-20
。
可以通过使用新变量为x域计算endDate
来解决此问题。
let newEndDate = new Date(endDate)
newEndDate.setDate(newEndDate.getDate() + 5); // adding more time at the end of the X axix
<!DOCTYPE html>
<meta charset="utf-8">
<style>
pre {display:none;}
/* Basic Styling with CSS */
body {
font: 15px sans-serif;
color: #444444;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
shape-rendering: crispEdges;
}
/* Style the lines by removing the fill and applying a stroke */
.line {
fill: none;
stroke: #ffab00;
stroke-width: 3;
}
.line2 {
fill: none;
stroke: #398fff;
stroke-width: 3;
}
.reg {
fill: none;
stroke: grey;
stroke-width: 3;
}
/* Style the dots by assigning a fill and stroke */
.dot {
fill: #ffab00;
stroke: #fff;
}
.dot2 {
fill: #398fff;
stroke: #fff;
}
/* Styling the title*/
div.title {
text-align: center;
font: 20px sans-serif;
padding-top: 20px;
}
/* Styling text in popup box*/
div.tooltip {
color:white;
position: absolute;
text-align: center;
padding: 6px;
font: 15px sans-serif;
background: #ffab00;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
div.tooltip2 {
color:white;
position: absolute;
text-align: center;
padding: 6px;
font: 15px sans-serif;
background: #398fff;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
</style>
<pre id="data">
,date,closed,created
25/06/2020,25-Jun-20,0,40
26/06/2020,26-Jun-20,4,40
28/06/2020,28-Jun-20,8,40
29/06/2020,29-Jun-20,12,43
01/07/2020,01-Jul-20,17,43
03/07/2020,03-Jul-20,22,44
04/07/2020,04-Jul-20,25,44
06/07/2020,06-Jul-20,31,44
</pre>
<div class="title"> Burn-up chart </div>
<div>
<!-- Load in the d3 and simple-statistics library -->
<script src="https://d3js.org/d3.v3.js"></script>
<script src="https://npmcdn.com/simple-statistics@2.0.0-beta3/dist/simple-statistics.min.js"></script>
<script>
var margin = {top: 50, right: 50, bottom: 50, left: 50},
width = window.innerWidth - margin.left - margin.right - 20,
height = window.innerHeight - margin.top - margin.bottom -80;
var parseDate = d3.time.format("%d-%b-%y").parse;
var dateFormat = d3.time.format("%a %d %b");
// define x y axis
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickFormat(d3.time.format("%d %b"));
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var div2 = d3.select("body").append("div")
.attr("class", "tooltip2")
.style("opacity", 0);
// d3's line generator
var line = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.closed); })
.interpolate("monotone");
var line2 = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.created); })
.interpolate("monotone");
// Add the SVG to the page
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 dataset
var data = d3.csv.parse( d3.select("#data").text() );
data.forEach(function (d) {
if (d.closed){
d.date = d.date = parseDate(d.date);
d.closed = +d.closed;
d.created = +d.created;
}});
data.pop(); //remove last "undefined" row
//console.log(data);
// Get min and max for X axis range
var startDate = d3.min(data, function (d) { return d.date; });
var endDate = d3.max(data, function (d) { return d.date; });
//
//
let newEndDate = new Date(endDate)
newEndDate.setDate(newEndDate.getDate() + 5); // adding more time at the end of the X axix
//
//
//console.log(startDate.toString());
//console.log(endDate.toString());
//console.log(d3.extent(data, function(d) { return d.closed; }));
//console.log(d3.max(data, function (d) { return d.closed; }));
// Get min and max for Y axis range
var arr= [];
arr.push(d3.max(data, function (d) { return d.closed; }));
arr.push(d3.max(data, function (d) { return d.created; }));
arr.push(d3.min(data, function (d) { return d.closed; }));
arr.push(d3.min(data, function (d) { return d.created; }));
//console.log(arr);
// define how long the axis are
x.domain([startDate,newEndDate]);
y.domain(d3.extent(arr));
// Derive a linear regression
var regression = ss.linearRegression(data.map(function(d) {
return [+d.date, d.closed];
}));
var lin = ss.linearRegressionLine(regression);
// Create a line based on the beginning and endpoints of that range
var lindata = x.domain().map(function(x) {
return {
date: new Date(x),
closed: lin(+x)
};
});
// Call the x axis in a group tag
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor","end")
.attr('transform', 'rotate(-45)');
// Call the y axis in a group tag
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Story Count");
// Append the path, bind the data, and call the line generator
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
// same for the second line
svg.append("path")
.datum(data)
.attr("class", "line2")
.attr("d", line2);
// and for the doted "trend" line
svg.append("path")
.datum(lindata)
.style("stroke-dasharray", ("3, 3"))
.attr("class", "reg")
.attr("d", line);
// Appends a circle for each datapoint line 1
svg.selectAll(".dot")
.data(data)
.enter().append("circle") // Uses the enter().append() method
.attr("class", "dot") // Assign a class for styling
.attr("cx", function(d) { return x(d.date); })
.attr("cy", function(d) { return y(d.closed); })
.attr("r", 5)
.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div.html(d.closed + " items - " + dateFormat(d.date))
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
// Appends a circle for each datapoint line 2
svg.selectAll(".dot2")
.data(data)
.enter().append("circle") // Uses the enter().append() method
.attr("class", "dot2") // Assign a class for styling
.attr("cx", function(d) { return x(d.date); })
.attr("cy", function(d) { return y(d.created); })
.attr("r", 5)
.on("mouseover", function(d) {
div2.transition()
.duration(200)
.style("opacity", .9);
div2.html(d.created + " items - " + dateFormat(d.date))
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div2.transition()
.duration(500)
.style("opacity", 0);
});
</script>
</div>