Published
Edited
Jan 14, 2022
2 forks
15 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
munged = pipe(
await d3.csv(
`https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_global.csv`
),
(arr) => {
const keepKeys = [`Country/Region`];
return arr
.map((row) => {
const isDateKey = (d) => d.match(/\d{1,2}\/\d{1,2}\/\d{1,2}/);
const dateKeys = Object.keys(row).filter(isDateKey);
const rest = Object.fromEntries(keepKeys.map((key) => [key, row[key]]));
return dateKeys.map((dateKey) => {
const value = row[dateKey];
const dateObject = d3.utcParse(`%m/%d/%y`)(dateKey);
const dateString = d3.utcFormat(`%Y-%m-%d`)(dateObject);
return { dateKey, dateString, value, ...rest };
});
return dateKeys;
})
.flat(2)
.map(d3.autoType)
.filter((d) => d[`Country/Region`] === `US`);
},
(arr) =>
d3
.rollups(
arr,
(arr) => d3.sum(arr, (d) => d.value),
(d) => d.dateString
)
.map(([dateString, value]) => ({ dateString, total: value }))
.sort((a, b) => d3.ascending(a[0], b[0]))
.map((d, index) => ({ ...d, index })),
(arr) => arr.map(getDelta({ key: `total`, outKey: `velocity` })),
(arr) => addTrends(arr, { yKey: `velocity`, bandwidth: 0.03 }),
(arr) => arr.map(getDelta({ key: `velocity`, outKey: `acceleration` })),
(arr) =>
addTrends(arr, { yKey: `acceleration`, bandwidth: 0.05, period: 14 }),
(arr) => arr.map(getDelta({ key: `accelerationLoess`, outKey: `jerk` })),
(arr) => addTrends(arr, { yKey: `jerk` })
)
Insert cell
Insert cell
function addTrends(array, { yKey, bandwidth, period }) {
return pipe(
array,
(array) =>
addLoess2(array, {
bandwidth,
xKey: `index`,
yKey,
outKey: `${yKey}Loess`
}),
(array) => array.map(movingAverage({ period, key: yKey })),
(array) =>
addLoess(array, {
xKey: `index`,
yKey: `${yKey}Mean`,
outKey: `${yKey}Loess_old`,
bandwidth
})
);
}
Insert cell
function addLoess2(
array,
{
bandwidth = 0.75,
xKey,
yKey,
outKey = `${yKey}Loess`,
xAccessor = (d) => d[xKey],
yAccessor = (d) => d[yKey]
}
) {
const filtered = array.filter(
(d) => Number.isFinite(xAccessor(d)) && Number.isFinite(yAccessor(d))
);
const x = filtered.map(xAccessor);
const y = filtered.map(yAccessor);
const model = new Loess(
{
x,
y
},
{ span: bandwidth }
);
const fitted = model.predict().fitted;
const indexToFit = Object.fromEntries(
fitted.map((d, i) => [filtered[i].index, d])
);
// const fitted = fit.fitted.map((d, i) => ({ index: xFiltered[i], value: d }));
// console.log("SLERB", indexToFit);
// console.log("far", filtered);
return array.map((d) => ({ ...d, [outKey]: indexToFit[d.index] }));
}
Insert cell
function addLoess(
array,
{
xKey,
yKey,
outKey = `${yKey}Loess`,
yAccessor = (d) => d[yKey],
bandwidth = 0.07
}
) {
// const normScale = d3.scaleLinear(d3.extent(array, yAccessor), [0, 1000]);
const loessGenerator = science.stats.loess().bandwidth(bandwidth);
const loess = loessGenerator(
array.map((d) => d[xKey]),
array.map((d) => d[yKey])
);
return array.map((d, i) => {
const loessValue = loess[i];
return { ...d, [outKey]: loessValue };
});
}
Insert cell
function movingAverage({ period = 14, key, outKey = `${key}Mean` }) {
const accessor = (d) => d[key];
return (d, i, arr) => {
const to = i + 1;
const from = to - period;
const sample = arr.slice(from, to);
const filtered = sample.filter((d) => Number.isFinite(accessor(d)));
const mean =
filtered.length === period ? d3.mean(filtered, accessor) : null;
return {
...d,
[outKey]: mean
};
};
}
Insert cell
function getDelta({ key, outKey }) {
return (d, i, arr) => {
const prev = arr[i - 1];
const delta = prev ? d[key] - prev[key] : null;
return {
...d,
[outKey]: delta
};
};
}
Insert cell
Insert cell
science = require("@sgratzl/science")
Insert cell
Loess = (await import("https://cdn.skypack.dev/loess")).default
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more