I want to create a cumulative line chart per year.
My data is an unordered list of days and values:
date value
2019-10-10 32.3104
2020-12-29 190.4676
2019-01-02 400.1440
2020-12-21 100.0
2020-12-21 347.1200
2019-01-02 30.6
...
I want to create a line per year, so I order the data and use rollup to sum and group the data:
data = {
const sortedData = rawdata.sort((a, b) => d3.ascending(a.date, b.date));
return d3.rollup(
sortedData,
(v) => d3.sum(v, (d) => d.value),
(d) => d.date.getFullYear(),
(d) => d.date
);
}
This way I get a chart with lines for each year using d3.join
svg.append("g")
.selectAll('.line')
.data(data.values())
.join(
(enter) =>
enter
.append('path')
.attr('class', 'line')
.attr('fill', 'none')
.attr('stroke', (d, i) => colors[i])
.attr('stroke-width', 1.5)
.attr('d', line),
(update) =>
update.attr('d', line),
);
Now I want this lines to be cumulative per year, but I got no idea how to use d3.cumsum
to add up the sums per year.
I don't know how to sum these rolled-up-data - can anyone help me here?
Here is a full working example of my chart on ObservableHQ
CodePudding user response:
If you want to keep the data in the same format that you currently have so that you don't have to change any other code, then you could do
data = {
const sortedData = rawdata.sort((a, b) => d3.ascending(a.date, b.date));
// rollups returns arrays of key-value pairs instead of a map
const groupByYearDate = d3.rollups(
sortedData,
(v) => d3.sum(v, (d) => d.value),
(d) => d.date.getFullYear(),
(d) => d.date
);
return new Map(
// for each year
groupByYearDate.map(([year, values]) => {
// summed is an array of numbers
const summed = d3.cumsum(values, d => d[1]);
// dates is an array of dates
const dates = values.map(d => d[0]);
// zip them together
const combined = d3.zip(dates, summed);
return [year, new Map(combined)]
})
);
}
Here's a slightly different example, that makes additional changes to your code.