added doubling time, graph color tweaks
This commit is contained in:
parent
df22e3c79f
commit
8bff273d8b
98
generate.js
98
generate.js
@ -154,23 +154,66 @@ const processGlobalDeaths = async () => {
|
||||
// return record['Country/Region'] === 'US';
|
||||
// });
|
||||
|
||||
const getGrowthRate = (record) => {
|
||||
const ts = record.timeSeriesDaily;
|
||||
const len = ts.length;
|
||||
const getRollingAverage = (item) => {
|
||||
return item.timeSeriesDaily.map((item, i, arr) => {
|
||||
const prevValues = arr.slice(Math.max(0, i - 6), i);
|
||||
const valueAverage = (item.value + prevValues.reduce((sum, next) => sum + next.value, 0)) / (1 + prevValues.length);
|
||||
const deltaAverage = (item.delta + prevValues.reduce((sum, next) => sum + next.delta, 0)) / (1 + prevValues.length);
|
||||
|
||||
return {
|
||||
key: item.key,
|
||||
value: Math.round(valueAverage),
|
||||
delta: Math.round(deltaAverage),
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
};
|
||||
|
||||
const getDoublingTime = (item) => {
|
||||
return item.timeSeriesDaily.map((item, i, arr) => {
|
||||
const prevItems = arr.slice(Math.max(i - 7, 0), i);
|
||||
const sum = prevItems.reduce((sum, next) => sum + next.value, 0);
|
||||
let value;
|
||||
if (sum < 10) {
|
||||
value = 0;
|
||||
} else {
|
||||
const growthRate = calcGrowthRate(arr, i, 7);
|
||||
if (growthRate <= 0 || !growthRate) {
|
||||
value = 0;
|
||||
} else {
|
||||
value = (Math.log(2) / Math.log(1 + growthRate));
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
key: item.key,
|
||||
value: Math.round(value * 10) / 10,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const calcGrowthRate = (ts, i, range) => {
|
||||
const items = ts.slice(Math.max(0, i - range), i + 1);
|
||||
const len = items.length;
|
||||
if (len < 2) {
|
||||
return 0;
|
||||
}
|
||||
const latest = len - 1;
|
||||
const earliest = Math.max(len - 14, 0);
|
||||
const earliest = 0;
|
||||
const pow = 1 / (latest - earliest + 1);
|
||||
const hi = ts[latest].value;
|
||||
const lo = Math.max(ts[earliest].value, 0.5);
|
||||
const hi = items[latest].value;
|
||||
const lo = Math.max(items[earliest].value, 0.5);
|
||||
if (hi === 0 && lo < 1) {
|
||||
return 0;
|
||||
}
|
||||
return Math.pow((hi / lo), pow) - 1;
|
||||
};
|
||||
|
||||
const getGrowthRate = (record) => {
|
||||
return calcGrowthRate(record.timeSeriesDaily, record.timeSeriesDaily.length - 1, 7);
|
||||
};
|
||||
|
||||
// state/county data is separated for the US and doesn't need to be rolled up
|
||||
tsUSRecords.forEach((usRecord) => {
|
||||
const newRecord = {
|
||||
@ -442,19 +485,9 @@ const processGlobalDeaths = async () => {
|
||||
}),
|
||||
};
|
||||
|
||||
stateItem.rollingAverageDaily = stateItem.timeSeriesDaily.map((item, i, arr) => {
|
||||
const prevValues = arr.slice(Math.max(0, i - 6), i);
|
||||
const valueAverage = (item.value + prevValues.reduce((sum, next) => sum + next.value, 0)) / (1 + prevValues.length);
|
||||
const deltaAverage = (item.delta + prevValues.reduce((sum, next) => sum + next.delta, 0)) / (1 + prevValues.length);
|
||||
|
||||
return {
|
||||
key: item.key,
|
||||
value: Math.round(valueAverage),
|
||||
delta: Math.round(deltaAverage),
|
||||
};
|
||||
});
|
||||
|
||||
stateItem.deathGrowthRate = getGrowthRate(stateItem);
|
||||
stateItem.rollingAverageDaily = getRollingAverage(stateItem);
|
||||
stateItem.doublingDaily = getDoublingTime(stateItem);
|
||||
|
||||
// insert into states array for the country
|
||||
perCountryTotals[item.country].states.push(stateItem);
|
||||
@ -492,19 +525,9 @@ const processGlobalDeaths = async () => {
|
||||
}),
|
||||
};
|
||||
|
||||
countryItem.rollingAverageDaily = countryItem.timeSeriesDaily.map((item, i, arr) => {
|
||||
const prevValues = arr.slice(Math.max(0, i - 6), i);
|
||||
const valueAverage = (item.value + prevValues.reduce((sum, next) => sum + next.value, 0)) / (1 + prevValues.length);
|
||||
const deltaAverage = (item.delta + prevValues.reduce((sum, next) => sum + next.delta, 0)) / (1 + prevValues.length);
|
||||
|
||||
return {
|
||||
key: item.key,
|
||||
value: Math.round(valueAverage),
|
||||
delta: Math.round(deltaAverage),
|
||||
};
|
||||
});
|
||||
|
||||
countryItem.deathGrowthRate = getGrowthRate(countryItem);
|
||||
countryItem.rollingAverageDaily = getRollingAverage(countryItem);
|
||||
countryItem.doublingDaily = getDoublingTime(countryItem);
|
||||
return countryItem;
|
||||
});
|
||||
|
||||
@ -554,19 +577,10 @@ const processGlobalDeaths = async () => {
|
||||
};
|
||||
});
|
||||
|
||||
worldData.rollingAverageDaily = worldData.timeSeriesDaily.map((item, i) => {
|
||||
const prevValues = worldData.timeSeriesDaily.slice(Math.max(0, i - 6), i);
|
||||
const valueAverage = (item.value + prevValues.reduce((sum, next) => sum + next.value, 0)) / (1 + prevValues.length);
|
||||
const deltaAverage = (item.delta + prevValues.reduce((sum, next) => sum + next.delta, 0)) / (1 + prevValues.length);
|
||||
|
||||
return {
|
||||
key: item.key,
|
||||
value: Math.round(valueAverage),
|
||||
delta: Math.round(deltaAverage),
|
||||
};
|
||||
});
|
||||
|
||||
worldData.deathGrowthRate = getGrowthRate(worldData);
|
||||
worldData.rollingAverageDaily = getRollingAverage(worldData);
|
||||
worldData.doublingDaily = getDoublingTime(worldData);
|
||||
|
||||
worldData.population = 7781841000;
|
||||
worldData.deathsPerMillion = worldData.total / worldData.population * 1000000;
|
||||
|
||||
|
@ -22,6 +22,16 @@ html
|
||||
}
|
||||
|
||||
script.
|
||||
Chart.pluginService.register({
|
||||
beforeDraw: (chart) => {
|
||||
const ctx = chart.chart.ctx;
|
||||
ctx.save();
|
||||
ctx.fillStyle = 'white';
|
||||
ctx.fillRect(0, 0, chart.width, chart.height);
|
||||
ctx.restore();
|
||||
}
|
||||
});
|
||||
|
||||
const charts = {
|
||||
logarithmic: false,
|
||||
heroChart: null,
|
||||
@ -90,7 +100,7 @@ html
|
||||
axis.type = 'logarithmic';
|
||||
const maxLogPower = Math.ceil(Math.log10(charts.heroMaxValue));
|
||||
axis.ticks.max = Math.pow(10, maxLogPower);
|
||||
axis.ticks.callback = value => Number(value.toString());
|
||||
axis.ticks.callback = value => Number(value.toString()).toLocaleString();
|
||||
} else {
|
||||
axis.type = 'linear';
|
||||
delete axis.ticks.max;
|
||||
@ -114,7 +124,7 @@ html
|
||||
axis.type = 'logarithmic';
|
||||
const maxLogPower = Math.ceil(Math.log10(data.maxValue));
|
||||
axis.ticks.max = Math.pow(10, maxLogPower);
|
||||
axis.ticks.callback = value => Number(value.toString());
|
||||
axis.ticks.callback = value => Number(value.toString()).toLocaleString();
|
||||
} else {
|
||||
axis.type = 'linear';
|
||||
delete axis.ticks.max;
|
||||
@ -125,9 +135,8 @@ html
|
||||
});
|
||||
}
|
||||
|
||||
function makeHeroChart(id, title, labels, totalDeaths, newDeaths, rollingAverage) {
|
||||
function makeHeroChart(id, title, labels, totalDeaths, newDeaths, rollingAverage, doubling) {
|
||||
const canvas = document.getElementById(id);
|
||||
|
||||
charts.heroMaxValue = totalDeaths[totalDeaths.length - 1];
|
||||
|
||||
charts.heroChart = new Chart(canvas.getContext('2d'), {
|
||||
@ -157,6 +166,14 @@ html
|
||||
fill: false,
|
||||
borderColor: 'rgb(96, 96, 96, 0.25)',
|
||||
borderWidth: 1,
|
||||
},
|
||||
{
|
||||
label: 'Days to 2x',
|
||||
data: doubling,
|
||||
fill: false,
|
||||
borderColor: 'rgb(187,40,193, 0.5)',
|
||||
borderWidth: 2,
|
||||
pointRadius: 0,
|
||||
}
|
||||
],
|
||||
},
|
||||
@ -183,7 +200,7 @@ html
|
||||
beginAtZero: true,
|
||||
min: 0,
|
||||
max: Math.pow(10, Math.ceil(Math.log10(charts.heroMaxValue))),
|
||||
callback: value => Number(value.toString())
|
||||
callback: value => Number(value.toString()).toLocaleString(),
|
||||
},
|
||||
afterBuildTicks: (axis, ticks) => {
|
||||
if (axis.type === 'logarithmic') {
|
||||
@ -254,6 +271,7 @@ html
|
||||
!{JSON.stringify(data.timeSeriesDaily.map(x => x.value))},
|
||||
!{JSON.stringify(data.timeSeriesDaily.map(x => x.delta))},
|
||||
!{JSON.stringify(data.rollingAverageDaily.map(x => x.delta))},
|
||||
!{JSON.stringify(data.doublingDaily.map(x => x.value))},
|
||||
);
|
||||
|
||||
mixin dataTable(items, label, type)
|
||||
|
Loading…
Reference in New Issue
Block a user