UNPKG

nightscout

Version:

Nightscout acts as a web-based CGM (Continuous Glucose Monitor) to allow multiple caregivers to remotely view a patients glucose data in realtime.

219 lines (196 loc) 7.65 kB
'use strict'; var times = require('../times'); var hourlystats = { name: 'hourlystats' , label: 'Hourly stats' , pluginType: 'report' }; function init () { return hourlystats; } module.exports = init; hourlystats.html = function html (client) { var translate = client.translate; var ret = '<h2>' + translate('Hourly stats') + '</h2>' + '<div id="hourlystats-overviewchart"></div>' + '<div id="hourlystats-report"></div>'; return ret; }; hourlystats.css = '#hourlystats-overviewchart {' + ' width: 100%;' + ' min-width: 6.5in;' + ' height: 5in;' + '}' + '#hourlystats-placeholder td {' + ' text-align:center;' + '}'; hourlystats.report = function report_hourlystats (datastorage, sorteddaystoshow, options) { //console.log(window); var ss = require('simple-statistics'); var Nightscout = window.Nightscout; var client = Nightscout.client; var translate = client.translate; var report_plugins = Nightscout.report_plugins; var report = $('#hourlystats-report'); var stats = []; var pivotedByHour = {}; var data = datastorage.allstatsrecords; for (var i = 0; i < 24; i++) { pivotedByHour[i] = []; } data = data.filter(function(o) { return !isNaN(o.sgv); }); data.forEach(function(record) { var d = new Date(record.displayTime); record.sgv = Number(record.sgv); pivotedByHour[d.getHours()].push(record); }); var table = $('<table width="100%" border="1">'); var thead = $('<tr/>'); $('<th>' + translate('Time') + '</th>').appendTo(thead); $('<th>' + translate('Readings') + '</th>').appendTo(thead); $('<th>' + translate('Average') + '</th>').appendTo(thead); $('<th>' + translate('Min') + '</th>').appendTo(thead); $('<th>' + translate('Quartile') + ' 25</th>').appendTo(thead); $('<th>' + translate('Median') + '</th>').appendTo(thead); $('<th>' + translate('Quartile') + ' 75</th>').appendTo(thead); $('<th>' + translate('Max') + '</th>').appendTo(thead); $('<th>' + translate('Standard Deviation') + '</th>').appendTo(thead); thead.appendTo(table); [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23].forEach(function(hour) { var tr = $('<tr>'); var display = new Date(0, 0, 1, hour, 0, 0, 0).toLocaleTimeString().replace(/([\d]+:[\d]{2})(:[\d]{2})(.*)/, '$1$3'); var avg = Math.floor(pivotedByHour[hour].map(function(r) { return r.sgv; }).reduce(function(o, v) { return o + v; }, 0) / pivotedByHour[hour].length); var d = new Date(times.hours(hour).msecs); var dev = ss.standard_deviation(pivotedByHour[hour].map(function(r) { return r.sgv; })); stats.push([ new Date(d) , ss.quantile(pivotedByHour[hour].map(function(r) { return r.sgv; }), 0.25) , ss.quantile(pivotedByHour[hour].map(function(r) { return r.sgv; }), 0.75) , avg - dev , avg + dev ]); var tmp; $('<td>' + display + '</td>').appendTo(tr); $('<td>' + pivotedByHour[hour].length + ' (' + Math.floor(100 * pivotedByHour[hour].length / data.length) + '%)</td>').appendTo(tr); $('<td>' + avg + '</td>').appendTo(tr); $('<td>' + Math.min.apply(Math, pivotedByHour[hour].map(function(r) { return r.sgv; })) + '</td>').appendTo(tr); // eslint-disable-next-line no-cond-assign $('<td>' + ((tmp = ss.quantile(pivotedByHour[hour].map(function(r) { return r.sgv; }), 0.25)) ? tmp.toFixed(1) : 0) + '</td>').appendTo(tr); // eslint-disable-next-line no-cond-assign $('<td>' + ((tmp = ss.quantile(pivotedByHour[hour].map(function(r) { return r.sgv; }), 0.5)) ? tmp.toFixed(1) : 0) + '</td>').appendTo(tr); // eslint-disable-next-line no-cond-assign $('<td>' + ((tmp = ss.quantile(pivotedByHour[hour].map(function(r) { return r.sgv; }), 0.75)) ? tmp.toFixed(1) : 0) + '</td>').appendTo(tr); $('<td>' + Math.max.apply(Math, pivotedByHour[hour].map(function(r) { return r.sgv; })) + '</td>').appendTo(tr); $('<td>' + Math.floor(dev * 10) / 10 + '</td>').appendTo(tr); table.append(tr); }); report.empty(); report.append(table); $.plot( '#hourlystats-overviewchart' , [{ data: stats , candle: true }], { series: { candle: true , lines: false //Somehow it draws lines if you dont disable this. Should investigate and fix this ;) } , xaxis: { mode: 'time' , timeFormat: '%h:00' , min: 0 , max: times.hours(24).msecs - times.secs(1).msecs } , yaxis: { min: 0 , max: options.units === 'mmol' ? 22 : 400 , show: true } , grid: { show: true } } ); var totalPositive = []; var totalNegative = []; var positivesCount = []; var negativesCount = []; var totalNet = []; var days = 0; table = $('<table width="100%" border="1">'); thead = $('<tr/>'); ["", 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23].forEach(function(hour) { $('<th>' + hour + '</th>').appendTo(thead); totalPositive[hour] = 0; totalNegative[hour] = 0; positivesCount[hour] = 0; negativesCount[hour] = 0; totalNet[hour] = 0; }); thead.appendTo(table); sorteddaystoshow.forEach(function(day) { if (datastorage[day].netBasalPositive) { days++; var tr = $('<tr>'); $('<td>' + report_plugins.utils.localeDate(day) + '</td>').appendTo(tr); for (var h = 0; h < 24; h++) { var positive = datastorage[day].netBasalPositive[h]; var negative = datastorage[day].netBasalNegative[h]; var net = positive + negative; totalPositive[h] += positive; totalNegative[h] += negative; if (positive + negative > 0) positivesCount[h] += 1; else if (positive + negative < 0) negativesCount[h] += 1; totalNet[h] += net; var color = Math.abs(net) < 0.019 ? "black" : (net < 0 ? "red" : "lightgreen"); $('<td>' + '<span style="color:black;">' + negative.toFixed(2) + '</span>' + '<br>' + '<span style="color:black;">' + positive.toFixed(2) + '</span>' + '<br>' + '<span style="color:' + color + ';font-weight:bold;">' + net.toFixed(2) + '</span>' + '</td>').appendTo(tr); } table.append(tr); } }); if (days > 0) { var tr = $('<tr>'); $('<td>' + '<span style="font-weight:bold;">' + translate('Average') + " " + days + " " + translate('days') + '</span>' + '</td>').appendTo(tr); for (var h = 0; h < 24; h++) { var color = Math.abs(totalNet[h]) < 0.01 ? "white" : (totalNet[h] < 0 ? "red" : "lightgreen"); $('<td style="background-color:' + color + '";>' + '<span style="color:black;">' + (totalNegative[h] / days).toFixed(2) + ' (' + negativesCount[h] + ')' + '</span>' + '<br>' + '<span style="color:black;">' + (totalPositive[h] / days).toFixed(2) + ' (' + positivesCount[h] + ')' + '</span>' + '<br>' + '<span style="color:black;font-weight:bold;">' + (totalNet[h] / days).toFixed(2) + '</span>' + '</td>').appendTo(tr); } table.append(tr); } report.append('<br>'); report.append('<h2>' + translate('netIOB stats') + '</h2>'); report.append(translate('(temp basals must be rendered to display this report)')); report.append('<br><br>'); report.append(table); };