Commit bda299aa authored by Michał Woźniak's avatar Michał Woźniak
Browse files

Merge branch 'wip-incidence' into 'master'

Add incidence chart

See merge request !1
parents d28cb0f8 dea0baa3
Pipeline #291 passed with stage
in 5 seconds
......@@ -10,7 +10,7 @@ This project is developed in the [PMF methodology](http://programming-motherfuck
Therefore, there are **no** external dependencies to pull, you **do not** need a local webserver, and you **do not** need `node` to use `npm` to get `yarn` to get `bower` to install `webpack`, because this techie happens to know how to left-pad without [`leftpad`](https://www.theregister.co.uk/2016/03/23/npm_left_pad_chaos/).
**Just clone this repository locally and navigate in your browser to the `index.html` file (for example, `file:///home/user/Projects/covid/index.html`). It should just work. That's it.**
**Just clone this repository locally and navigate your browser to the `index.html` file (for example, `file:///home/user/Projects/covid/index.html`). It should just work. That's it.**
## Deployment
......@@ -18,7 +18,7 @@ Copy the files to the location they're going to be served from. That's it. It's
## Privacy
There are no trackers, and no third-party content. This is completely self-contained.
There are no trackers, and [no third-party content](https://barnacles.online/). This is completely self-contained.
And it is self-contained because there is absolutely zero need for it not to be.
......@@ -33,6 +33,9 @@ Remember this when somebody tells you again that they need Google Fonts ([nope](
>
> WHO mission to China issued a statement saying that there was evidence of human-to-human transmission in Wuhan but more investigation was needed to understand the full extent of transmission.
- ***There are errors in the data / some data is missing!***
As mentioned above, I am using external source of data that I do not control. That being said there is a reasonably large chance that the error is in how I process/display the data. If you think that might be the case, let me know.
- ***Some things do not work in Safari. Why?***
Because [Safari is broken](https://bugs.webkit.org/show_bug.cgi?id=119175), that's why.
......@@ -41,6 +44,11 @@ Remember this when somebody tells you again that they need Google Fonts ([nope](
## Changelog
### 14.12.2020
- Added `incidence` chart for cases, recoveries, and deaths.
Fixes #3.
### 06.12.2020
- Changed the way rolling average is calculated: a rolling average over `n` days for the current day is now calculated from data from the day and `n-1` proceeding days, instead of centering the rolling average on the selected day.
......
......@@ -1349,6 +1349,19 @@ let updateChartData = (siteSelect) => {
// which data are we looking at
var dataset = document.querySelector('input[type=radio][name=chart-data]:checked').value
// make sure the interface choices make sense
// NOTICE: fixing things here should be the last resort!
// settings that do not make sense should be made impossible
// in the interface by means of HTML+CSS first and foremost
// and by checks in the right places (ignoring settings that
// do not make sense in JS)
//
// only when this is not enough and adding such checks is too complicated
// should the blunt instrument of fixing them explicitly here be used
if ( (document.querySelector('input[type=radio][name=chart-cases]:checked').value === "incidence") && ( (dataset === "active") || (dataset === "cfr") ) ) {
document.querySelector('input[type=radio]#chart-cases-delta').checked = true
}
// population_ratio is also used as an indicator that we're doing a per-million chart
var population_ratio = false
if (dataset !== 'cfr') {
......@@ -1408,35 +1421,64 @@ let updateChartData = (siteSelect) => {
to_chart.data = to_chart.data.map(row => Math.round(row / population_ratio))
}
// are we doing the moving average thing?
// are we doing the incidence / rolling average thing?
var avg_over = document.querySelector('input[type=number][name=chart-average]').value
if ( (document.querySelector('input[type=radio][name=chart-cases]:checked').value === 'new') && (avg_over > 1) ) {
if (avg_over > 1) {
// average
if (document.querySelector('input[type=radio][name=chart-cases]:checked').value === 'new') {
to_chart.data = to_chart.data.reduce((acc, cur, idx, arr) => {
to_chart.data = to_chart.data.reduce((acc, cur, idx, arr) => {
var mean = 0;
var avg_start = idx - avg_over + 1
var avg_end = idx
var mean = 0;
var avg_start = idx - avg_over + 1
var avg_end = idx
// if we don't have enough previous data to average over
// use whatever we have
if (idx < avg_over) {
avg_start = 0
}
// if we don't have enough previous data to average over
// use whatever we have
if (idx < avg_over) {
avg_start = 0
}
// calculate the mean
for (var j=avg_start; j<=avg_end; j++) {
mean += arr[j];
}
// if we're talking case fatality rate, we should not round
if (dataset === 'cfr') {
acc.push(mean / (avg_end - avg_start + 1))
// everything else nicely rounded
} else {
acc.push(Math.round(mean / (avg_end - avg_start + 1)))
}
return acc
}, [])
// calculate the mean
for (var j=avg_start; j<=avg_end; j++) {
mean += arr[j];
}
// if we're talking case fatality rate, we should not round
if (dataset === 'cfr') {
acc.push(mean / (avg_end - avg_start + 1))
// everything else nicely rounded
} else {
acc.push(Math.round(mean / (avg_end - avg_start + 1)))
}
return acc
}, [])
// incidence
} else if (document.querySelector('input[type=radio][name=chart-cases]:checked').value === 'incidence') {
to_chart.data = to_chart.data.reduce((acc, cur, idx, arr) => {
var incidence = 0;
var icdc_start = idx - avg_over + 1
var icdc_end = idx
// if we don't have enough previous data to calculate incidence within
// use whatever we have
if (idx < avg_over) {
icdc_start = 0
}
// calculate the incidence
for (var j=icdc_start; j<=icdc_end; j++) {
incidence += arr[j];
}
acc.push(incidence)
return acc
}, [])
}
}
// assign the data to the chart
......@@ -1567,6 +1609,12 @@ let updateChartSettings = () => {
theChart.options.scales.yAxes[0].ticks.min = 0
}
// incidence numbers
// these *only* make sense for confirmed / recovered / deaths
} else if ( (document.querySelector('input[type=radio][name=chart-cases]:checked').value === 'incidence') && ( (chart_dataset === 'confirmed') || (chart_dataset === 'recovered') || (chart_dataset === 'deaths') ) ) {
theChart.options.scales.yAxes[0].scaleLabel.labelString += ", incidence"
theChart.options.title.text[0] = `incidence of ${theChart.options.title.text[0]}`
// showing new confirmed cases / recoveries / deaths / active cases / cfr
// notice: *new active cases* can be *negative!*
} else {
......@@ -2157,7 +2205,7 @@ document.addEventListener('DOMContentLoaded', (e)=>{
if (setting === '') {
return false;
}
// perhaps it' a "valued" setting?
// perhaps it's a "valued" setting?
setting = setting.split(':')
// get the node
var node = document.querySelector(`.chart-config-container input[id$=${setting[0]}]`)
......
......@@ -327,6 +327,9 @@
.chart-config-container input#chart-data-cfr:checked ~ .chart-config-group label[for=chart-data-cfr],
.chart-config-container input#chart-cases-cumulative:checked ~ .chart-config-group label[for=chart-cases-cumulative],
.chart-config-container input#chart-cases-delta:checked ~ .chart-config-group label[for=chart-cases-delta],
.chart-config-container input#chart-data-active:not(:checked) ~ input#chart-data-cfr:not(:checked) ~ input#chart-cases-incidence:checked ~ .chart-config-group label[for=chart-cases-incidence],
.chart-config-container input#chart-data-active:checked ~ input#chart-cases-incidence:checked ~ .chart-config-group label[for=chart-cases-delta],
.chart-config-container input#chart-data-cfr:checked ~ input#chart-cases-incidence:checked ~ .chart-config-group label[for=chart-cases-delta],
.chart-config-container input#chart-data-active:not(:checked) ~ input#chart-data-cfr:not(:checked) ~ input#chart-type-logarithmic:checked ~ .chart-config-group label[for=chart-type-logarithmic],
.chart-config-container input#chart-data-active:not(:checked) ~ input#chart-cases-delta:not(:checked) ~ input#chart-type-logarithmic:checked ~ .chart-config-group label[for=chart-type-logarithmic],
.chart-config-container input#chart-data-cfr:not(:checked) ~ input#chart-cases-delta:not(:checked) ~ input#chart-type-logarithmic:checked ~ .chart-config-group label[for=chart-type-logarithmic],
......@@ -346,6 +349,8 @@
color:black;
box-shadow: 0px 0px 2px springgreen;
}
.chart-config-container input#chart-data-active:checked ~ .chart-config-group label[for=chart-cases-incidence],
.chart-config-container input#chart-data-cfr:checked ~ .chart-config-group label[for=chart-cases-incidence],
.chart-config-container input#chart-data-active:checked ~ input#chart-cases-delta:checked ~ .chart-config-group label[for=chart-type-logarithmic],
.chart-config-container input#chart-data-cfr:checked ~ input#chart-cases-delta:checked ~ .chart-config-group label[for=chart-type-logarithmic],
.chart-config-container input#chart-data-cfr:checked ~ .chart-config-group label[for=chart-values-per100k],
......@@ -408,6 +413,14 @@
.chart-config-container input#chart-data-cfr:checked ~ .chart-config-group .delta-change {
display:inline;
}
.chart-config-group .chart-average-average,
.chart-config-group .chart-average-incidence {
display:none;
}
.chart-config-container input#chart-cases-delta:checked ~ .chart-config-group .chart-average-average,
.chart-config-container input#chart-cases-incidence:checked ~ .chart-config-group .chart-average-incidence {
display:inline;
}
.chart-config-group .per100k,
.chart-config-group .permillion,
.chart-config-group .data-confirmed,
......@@ -432,7 +445,8 @@
.chart-config-group.chart-average {
display:none;
}
.chart-config-container input#chart-cases-delta:checked ~ .chart-config-group.chart-average {
.chart-config-container input#chart-cases-delta:checked ~ .chart-config-group.chart-average,
.chart-config-container input#chart-cases-incidence:checked ~ .chart-config-group.chart-average {
display:flex;
}
.chart-config-container #chart-average {
......@@ -505,6 +519,7 @@
<input type="radio" id="chart-data-cfr" name="chart-data" value="cfr"/>
<input type="radio" id="chart-cases-cumulative" name="chart-cases" value="cumulative" checked="checked"/>
<input type="radio" id="chart-cases-delta" name="chart-cases" value="new"/>
<input type="radio" id="chart-cases-incidence" name="chart-cases" value="incidence"/>
<input type="radio" id="chart-type-logarithmic" name="chart-type" value="logarithmic" checked="checked"/>
<input type="radio" id="chart-type-linear" name="chart-type" value="linear"/>
<input type="radio" id="chart-values-absolute" name="chart-values" value="absolute" checked="checked"/>
......@@ -533,11 +548,12 @@
<p><span class="cases-cases">Cases</span><span class="cases-recoveries">Recoveries</span><span class="cases-deaths">Deaths</span><span class="cases-chart">Chart</span>:</p>
<label for="chart-cases-cumulative"><span class="values-cumulative">cumulative</span><span class="values-count">count</span><span class="values-values">values</span></label>
<label for="chart-cases-delta"><span class="delta-new">new</span><span class="delta-change">change</span></label>
<label for="chart-cases-incidence">incidence</label>
</div>
<div class="chart-config-group chart-average">
<p>Average over:</p>
<p><span class="chart-average-average">Average over:</span><span class="chart-average-incidence">Incidence within:</span></p>
<input type="number" min="1" max="31" step="1" value="1" name="chart-average" id="chart-average"/>
<p>datapoints</p>
<p>days</p>
</div>
<div class="chart-config-group">
<p>Values:</p>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment