我想在D3.js
中绘制图表。它是Date VS值图。但是,当Date相同时,我的几个值不同。我想考虑Date相似的值的总和。这是数据的样子,
[
{
Date : "2017-12-15",
Sales : "50"
},
{ Date : "2017-12-16",
Sales : "20"
},
{
Date : "2017-12-17",
Sales : "30"
},
{
Date : "2017-12-18",
Sales : "10"
},
{
Date : "2017-12-18",
Sales : "40"
},
{
Date : "2017-12-19",
Sales : "60"
}
]
你可以看到,在2017-12-18
上有两个Sales
值,10
和40
。我想考虑(10 + 40)
的2017-12-18
的总和(每当有相同的Sales
时有不同的Date
值)。
JS: -
var data = [
{
Date : "2017-12-15",
Sales : "50"
},
{ Date : "2017-12-16",
Sales : "20"
},
{
Date : "2017-12-17",
Sales : "30"
},
{
Date : "2017-12-18",
Sales : "10"
},
{
Date : "2017-12-18",
Sales : "40"
},
{
Date : "2017-12-19",
Sales : "60"
}
].map(function(entry) {
return {
Date: d3.timeParse("%Y-%m-%d")(entry.Date),
Sales: +entry.Sales
}
});
var svg = d3.select("svg"),
margin = {top: 20, right: 20, bottom: 30, left: 50},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var x = d3.scaleTime()
.rangeRound([0, width]);
var y = d3.scaleLinear()
.rangeRound([height, 0]);
var line = d3.line()
.x(function(d) { return x(d.Date); })
.y(function(d) { return y(d.Sales); });
x.domain(d3.extent(data, function(d) { return d.Date; }));
y.domain(d3.extent(data, function(d) { return d.Sales; }));
g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
g.append("g")
.call(d3.axisLeft(y))
g.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", 1.5)
.attr("d", line);
HTML: -
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.12.0/d3.min.js"></script>
<svg width="600" height="180"></svg>
这里发生的是,只有当Date相同时才取较高的值,而不取和值。
有几种方法可以对该数组中的对象求和。也许,JavaScript中最惯用的方式是使用reduce:
var data = [{
Date: "2017-12-15",
Sales: "50"
}, {
Date: "2017-12-16",
Sales: "20"
}, {
Date: "2017-12-17",
Sales: "30"
}, {
Date: "2017-12-18",
Sales: "10"
}, {
Date: "2017-12-18",
Sales: "40"
}, {
Date: "2017-12-19",
Sales: "60"
}];
var reduced = data.reduce(function(allDates, date) {
if (allDates.some(function(e) {
return e.Date === date.Date
})) {
allDates.filter(function(e) {
return e.Date === date.Date
})[0].Sales += +date.Sales
} else {
allDates.push({
Date: date.Date,
Sales: +date.Sales
})
}
return allDates
}, []);
console.log(reduced)
之后,只需要创建一个基本的SVG路径:
var rawData = [
{
Date: "2017-12-15",
Sales: "50"
}, {
Date: "2017-12-16",
Sales: "20"
}, {
Date: "2017-12-17",
Sales: "30"
}, {
Date: "2017-12-18",
Sales: "10"
}, {
Date: "2017-12-18",
Sales: "40"
}, {
Date: "2017-12-19",
Sales: "60"
}
];
var data = rawData.reduce(function(allDates, date) {
if (allDates.some(function(e) {
return e.Date === date.Date
})) {
allDates.filter(function(e) {
return e.Date === date.Date
})[0].Sales += +date.Sales
} else {
allDates.push({
Date: date.Date,
Sales: +date.Sales
})
}
return allDates
}, []);
data.forEach(function(d) {
d.Date = d3.timeParse("%Y-%m-%d")(d.Date)
})
var svg = d3.select("svg"),
margin = {
top: 20,
right: 20,
bottom: 30,
left: 50
},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var x = d3.scaleTime()
.rangeRound([0, width]);
var y = d3.scaleLinear()
.rangeRound([height, 0]);
var line = d3.line()
.x(function(d) {
return x(d.Date);
})
.y(function(d) {
return y(d.Sales);
});
x.domain(d3.extent(data, function(d) {
return d.Date;
}));
y.domain(d3.extent(data, function(d) {
return d.Sales;
}));
g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
g.append("g")
.call(d3.axisLeft(y))
g.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", 1.5)
.attr("d", line);
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="600" height="180"></svg>
您可以使用d3.nest()将值与汇总和求和函数相加。
var data = [
{Date : "2017-12-15", Sales : "50"},
{Date : "2017-12-16", Sales : "20"},
{Date : "2017-12-17", Sales : "30"},
{Date : "2017-12-18", Sales : "10"},
{Date : "2017-12-18", Sales : "40"},
{Date : "2017-12-19", Sales : "60"}
]
var nested = d3.nest()
.key(function(d) {
return d.Date;
})
.rollup(function(v) {
return d3.sum(v, function(d) {
return d.Sales;
});
})
.entries(data);
console.log(nested);
结果数组如下所示:
[
{key: "2017-12-15", value: 50},
{key: "2017-12-16", value: 20},
{key: "2017-12-17", value: 30},
{key: "2017-12-18", value: 50},
{key: "2017-12-19", value: 60}
]
需要注意的是嵌套对象现在使用“key”和“value”作为键。
您可以使用array#reduce
来计算同一日期的Sales
值。
var data = [{Date : "2017-12-15", Sales : "50"},{Date : "2017-12-16", Sales : "20"},{Date : "2017-12-17", Sales : "30"},{Date : "2017-12-18", Sales : "10"},{Date : "2017-12-18", Sales : "40"},{Date : "2017-12-19", Sales : "60"}];
var result = Object.values(data.reduce((r, o) => {
r[o.Date] = r[o.Date] || {Date: o.Date, Sales : 0};
r[o.Date].Sales += +o.Sales;
return r;
},{}));
console.log(result);
var data = [{Date : "2017-12-15", Sales : "50"},{Date : "2017-12-16", Sales : "20"},{Date : "2017-12-17", Sales : "30"},{Date : "2017-12-18", Sales : "10"},{Date : "2017-12-18", Sales : "40"},{Date : "2017-12-19", Sales : "60"}];
var data = Object.values(data.reduce((r, o) => {
r[o.Date] = r[o.Date] || {Date: o.Date, Sales : 0};
r[o.Date].Sales += +o.Sales;
return r;
},{}));
data.forEach(function(d) {
d.Date = d3.timeParse("%Y-%m-%d")(d.Date)
})
var svg = d3.select("svg"),
margin = {
top: 20,
right: 20,
bottom: 30,
left: 50
},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var x = d3.scaleTime()
.rangeRound([0, width]);
var y = d3.scaleLinear()
.rangeRound([height, 0]);
var line = d3.line()
.x(function(d) {
return x(d.Date);
})
.y(function(d) {
return y(d.Sales);
});
x.domain(d3.extent(data, function(d) {
return d.Date;
}));
y.domain(d3.extent(data, function(d) {
return d.Sales;
}));
g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
g.append("g")
.call(d3.axisLeft(y))
g.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", 1.5)
.attr("d", line);
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="600" height="180"></svg>