Published
Edited
Oct 7, 2020
Insert cell
Insert cell
html`<table cellpadding="4"><tr><th>Date</th><th>Errors per RH</th><th>Errors</th></tr>${
errors_list.map(e => {
return '<tr valign="top" style="white-space: nowrap; cell"><td>'+dateStr(e.date)+'</td><td>'+printErrors(e.errors)+'</td></tr>';
}).reverse().join('')
}</table>`
Insert cell
printErrors = function(errors) {
const perRH = errors.filter(
a => a.rh || (a.today && a.val != 'rh.occupant.total' && a.val != 'rh.employee.total')
).map(a => {
if (a.today) {
return '<b>DECREASE</b> ' + a.val + ' ' + a.yesterday + ' → ' + a.today;
}
return '<b>' + a.rh + '</b> ' + formatDif3(a);
}).join('<br/>');
const allRH = errors.filter(a => !(a.rh || (a.today && a.val != 'rh.occupant.total' && a.val != 'rh.employee.total'))).map(a => {
if (a.today) {
return '<b>DECREASE</b> ' + a.val + ' ' + a.yesterday + ' → ' + a.today;
}
if (Object.keys(a).length == 3) {
return '<b>TOTAL DSO</b> ' + formatDif3(a);
}
const type = (a.agg_occupant || a.agg_employee) ? '<b>AGG DSO</b>: '
: (a.stats_occupant || a.stats_employee) ? '<b>STATS</b>: '
: '';
return type + Object.entries(a).map(kv => formatOccEmp(kv[0])+':'+kv[1]).join(' ≠ ');
}).join('<br />');
return perRH + '</td><td>' + allRH;
}
Insert cell
occImg = function() {
return Math.random() < 0.5 ? '👴' : '👵';
}
Insert cell
formatOccEmp = function(str) {
return str.replaceAll('occupant', occImg()).replaceAll('employee','🩺').replaceAll('agg_','∑');
}
Insert cell
formatDif3 = function(a) {
return '🩺 '+a.employee+' + '+occImg()+' '+a.occupant+' ≠ '+formatDif2(a.total, a.employee + a.occupant);
}
Insert cell
formatDif2 = function(exp, actual) {
if ((+actual) || actual===0) {
return '<b>' + exp + '</b> (' + (actual < exp ? (actual-exp) : ('+' + (actual-exp)))+')';
}
return exp;
}
Insert cell
errors_list = all_data.map((a, idx, arr) => {
let sumTot = 0;
let sumEmp = 0;
let sumOcc = 0;
const errors = [];
homes.forEach(h => {
const hTot = a['rh.' + h.id + '.total'];
const hEmp = a['rh.' + h.id + '.employee'];
const hOcc = a['rh.' + h.id + '.occupant'];
if (+hTot != +hEmp + +hOcc) {
errors.push({rh: h.id, total: hTot, employee: hEmp, occupant: hOcc});
}
sumTot += +hTot;
sumEmp += +hEmp;
sumOcc += +hOcc;
});
const mainStat = stats_data[dateStr(a.date)];

// Check DECREASE
if (idx > 0) {
for (const prop in a) {
checkDecrease(a, arr[idx-1], prop, errors);
}
const mainStatPrev = stats_data[dateStr(arr[idx-1].date)];
checkDecrease(mainStat, mainStatPrev, 'cases.rh.employee.confirmed.todate', errors);
checkDecrease(mainStat, mainStatPrev, 'cases.rh.occupant.confirmed.todate', errors);
}
const tot = a['rh.total'];
const emp = a['rh.employee.total'];
const occ = a['rh.occupant.total'];
if (tot != emp + occ) {
errors.push({total: tot, employee: emp, occupant: occ});
}
if (sumTot != tot) {
errors.push({total: tot, agg_total: sumTot});
}
if (sumEmp != emp) {
errors.push({employee: emp, agg_employee: sumEmp});
}
if (sumOcc != occ) {
errors.push({occupant: occ, agg_occupant: sumOcc});
}
if (occ != +mainStat['cases.rh.occupant.confirmed.todate']) {
errors.push({occupant: occ, stats_occupant: mainStat['cases.rh.occupant.confirmed.todate']});
}
if (emp != +mainStat['cases.rh.employee.confirmed.todate']) {
errors.push({employee: emp, stats_employee: mainStat['cases.rh.employee.confirmed.todate']});
}
return errors.length == 0
? null
: ({date: a.date, errors: errors});
}).filter(a => a);
Insert cell
checkDecrease = function (newObj, oldObj, prop, errors) {
if (+newObj[prop] < +oldObj[prop]) {
errors.push({val: prop, today: newObj[prop], yesterday: oldObj[prop]});
}
}
Insert cell
Insert cell
all_data = d3.csv('https://raw.githubusercontent.com/sledilnik/data/master/csv/retirement_homes.csv', d3.autoType).then(arr => arr.map(
(a, idx, arr) => {
for (const propName in a) {
if (idx > 0 && a[propName] === null) {
a[propName] = arr[idx-1][propName];
}
}
return a;
}))
Insert cell
stats_data = d3.csv('https://raw.githubusercontent.com/sledilnik/data/master/csv/stats.csv', d3.autoType).then(
arr => {
const retObj = {};
arr.forEach(d => {
retObj[dateStr(d.date)] = d
});
return retObj;
}
)
Insert cell
dateStr = d3.utcFormat("%Y-%m-%d")
Insert cell
d3 = require('d3','d3-time')
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