function plotDistricts(data, dateRange, options = {}) {
options = { yLabel: "Infections", includeTotal: true, ...options };
data = filterRange(data, dateRange);
const yMax = _.max(data.map((d) => d.infections));
function memoize(fn) {
const cache = new Map();
return (arg) => {
if (cache.has(arg)) return cache.get(arg);
const value = fn(arg);
cache.set(arg, value);
return value;
};
}
const districtInfections = memoize((name) => {
return _.sum(
data.filter((d) => d.district === name).map((d) => d.infections)
);
});
data = data.filter((d) => districtInfections(d.district) > 0);
const dNames = districtNames;
const cols = Math.ceil(Math.sqrt(dNames.length));
data = data.map((d) => ({
...d,
index: dNames.indexOf(d.district)
}));
return Plot.plot({
grid: true,
width,
height: 600,
marginBottom: 80,
color: {
range: ["orange", "red"],
interpolate: "hcl"
},
facet: {
data,
x: (d) => " ".repeat(d.index % cols),
y: (d) => " ".repeat(Math.floor(d.index / cols))
},
x: {
label: "Date",
ticks: 10,
tickRotate: 45
},
y: {
label: options.yLabel,
tickFormat: ".0f"
},
marks: [
Plot.frame(),
Plot.areaY(data, {
x: "date",
y: "infections",
curve: "step-before",
fill: (d) => districtInfections(d.district)
}),
Plot.text(data, {
text: (d) =>
options.includeTotal && districtInfections(d.district)
? `${d.district} (${districtInfections(d.district)})`
: d.district,
fontSize: 18,
y: yMax * 0.85
})
]
});
}