Skip to content

Commit efed4c4

Browse files
authored
Merge pull request #443 from tidepool-org/WEB-2965-exclude-days
WEB-2965 - Exclude Days with no insulin data in Basics
2 parents db988a5 + 0327547 commit efed4c4

File tree

10 files changed

+57
-30
lines changed

10 files changed

+57
-30
lines changed

data/print/fixtures.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ export const basicsData = {
5252
timePrefs,
5353
bgPrefs,
5454
metaData,
55-
query: { excludeDaysWithoutBolus: true },
5655
data: {
5756
current: {
5857
endpoints: {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"node": "20.8.0"
55
},
66
"packageManager": "[email protected]",
7-
"version": "1.45.0-web-3418-redirect-oauth.2",
7+
"version": "1.45.0-web-2965-exclude-days.2",
88
"description": "Tidepool data visualization for diabetes device data.",
99
"keywords": [
1010
"data visualization"

src/modules/print/BasicsPrintView.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ class BasicsPrintView extends PrintView {
145145
this.renderCalendarSection({
146146
title: {
147147
text: this.sections.boluses.title,
148-
subText: _.get(this.data, 'query.excludeDaysWithoutBolus') ? t('(days with no boluses have been excluded)') : false,
148+
subText: t('(days with no insulin data have been excluded)'),
149149
},
150150
data: this.aggregationsByDate.boluses.byDate,
151151
type: 'bolus',
@@ -648,10 +648,7 @@ class BasicsPrintView extends PrintView {
648648
const xPos = pos.x + padding.left;
649649
const yPos = pos.y + padding.top;
650650

651-
const isEmptyBolusDay = color === this.colors.bolus && count === 0;
652-
const isExcludedBolusDay = isEmptyBolusDay && _.get(this.data, 'query.excludeDaysWithoutBolus', false);
653-
654-
this.setFill((type === 'outOfRange' || isExcludedBolusDay) ? this.colors.lightGrey : 'black', 1);
651+
this.setFill((type === 'outOfRange') ? this.colors.lightGrey : 'black', 1);
655652

656653
this.doc
657654
.fontSize(this.extraSmallFontSize)

src/utils/StatUtil.js

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { getTotalBasalFromEndpoints, getBasalGroupDurationsFromEndpoints } from
66
import { getTotalBolus } from './bolus';
77
import { cgmSampleFrequency, classifyBgValue } from './bloodglucose';
88
import { BGM_DATA_KEY, MGDL_UNITS, MGDL_PER_MMOLL, MS_IN_DAY, MS_IN_MIN } from './constants';
9+
import { formatLocalizedFromUTC } from './datetime';
910

1011
/* eslint-disable lodash/prefer-lodash-method, no-underscore-dangle, no-param-reassign */
1112

@@ -24,8 +25,8 @@ export class StatUtil {
2425
this.bgUnits = _.get(dataUtil, 'bgPrefs.bgUnits');
2526
this.bgSource = _.get(dataUtil, 'bgSources.current', BGM_DATA_KEY);
2627
this.activeDays = dataUtil.activeEndpoints.activeDays;
27-
this.bolusDays = dataUtil.activeEndpoints.bolusDays || this.activeDays;
2828
this.endpoints = dataUtil.activeEndpoints.range;
29+
this.timePrefs = _.get(dataUtil, 'timePrefs');
2930

3031
this.log('activeDays', this.activeDays);
3132
this.log('bgSource', this.bgSource);
@@ -82,16 +83,24 @@ export class StatUtil {
8283
const rawBasalData = this.dataUtil.sort.byTime(this.dataUtil.filter.byType('basal').top(Infinity));
8384
const basalData = this.dataUtil.addBasalOverlappingStart(_.cloneDeep(rawBasalData));
8485

86+
// Create a list of all dates for which we have at least one datum
87+
const uniqueDatumDates = new Set([
88+
...bolusData.map(datum => formatLocalizedFromUTC(datum.time, this.timePrefs, 'YYYY-MM-DD')),
89+
...rawBasalData.map(datum => formatLocalizedFromUTC(datum.time, this.timePrefs, 'YYYY-MM-DD')),
90+
]);
91+
92+
const activeDaysWithInsulinData = uniqueDatumDates.size;
93+
8594
const basalBolusData = {
8695
basal: basalData.length
8796
? parseFloat(getTotalBasalFromEndpoints(basalData, this.endpoints))
8897
: NaN,
8998
bolus: bolusData.length ? getTotalBolus(bolusData) : NaN,
9099
};
91100

92-
if (this.bolusDays > 1) {
93-
basalBolusData.basal = basalBolusData.basal / this.bolusDays;
94-
basalBolusData.bolus = basalBolusData.bolus / this.bolusDays;
101+
if (activeDaysWithInsulinData > 1) {
102+
basalBolusData.basal = basalBolusData.basal / activeDaysWithInsulinData;
103+
basalBolusData.bolus = basalBolusData.bolus / activeDaysWithInsulinData;
95104
}
96105

97106
return basalBolusData;
@@ -101,6 +110,14 @@ export class StatUtil {
101110
const wizardData = this.dataUtil.filter.byType('wizard').top(Infinity);
102111
const foodData = this.dataUtil.filter.byType('food').top(Infinity);
103112

113+
// Create a list of all dates for which we have at least one datum
114+
const uniqueDatumDates = new Set([
115+
...wizardData.map(datum => formatLocalizedFromUTC(datum.time, this.timePrefs, 'YYYY-MM-DD')),
116+
...foodData.map(datum => formatLocalizedFromUTC(datum.time, this.timePrefs, 'YYYY-MM-DD')),
117+
]);
118+
119+
const activeDaysWithCarbData = uniqueDatumDates.size;
120+
104121
const wizardCarbs = _.reduce(
105122
wizardData,
106123
(result, datum) => {
@@ -132,10 +149,10 @@ export class StatUtil {
132149
exchanges: wizardCarbs.exchanges,
133150
};
134151

135-
if (this.activeDays > 1) {
152+
if (activeDaysWithCarbData > 1) {
136153
carbs = {
137-
grams: carbs.grams / this.activeDays,
138-
exchanges: carbs.exchanges / this.activeDays,
154+
grams: carbs.grams / activeDaysWithCarbData,
155+
exchanges: carbs.exchanges / activeDaysWithCarbData,
139156
};
140157
}
141158

src/utils/basics/data.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,6 @@ export function basicsText(patient, data, stats, aggregations) {
377377
},
378378
},
379379
metaData,
380-
query,
381380
timePrefs,
382381
} = data;
383382

@@ -386,9 +385,7 @@ export function basicsText(patient, data, stats, aggregations) {
386385
let basicsString = textUtil.buildDocumentHeader('Basics');
387386
basicsString += textUtil.buildDocumentDates();
388387

389-
if (_.get(query, 'excludeDaysWithoutBolus')) {
390-
basicsString += textUtil.buildTextLine(t('Days with no boluses have been excluded from bolus calculations'));
391-
}
388+
basicsString += textUtil.buildTextLine(t('Days with no insulin data have been excluded from calculations'));
392389

393390
basicsString += utils.statsText(stats, textUtil, bgPrefs);
394391

src/utils/stat.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -318,15 +318,15 @@ export const getStatAnnotations = (data, type, opts = {}) => {
318318

319319
case commonStats.averageDailyDose:
320320
if (days > 1) {
321-
annotations.push(t('**Avg. Daily Insulin:** All basal and bolus insulin delivery (in Units) added together, divided by the number of days in this view.'));
321+
annotations.push(t('**Avg. Daily Insulin:** All basal and bolus insulin delivery (in Units) added together, divided by the number of days in this view for which we have insulin data.'));
322322
} else {
323323
annotations.push(t('**Daily Insulin:** All basal and bolus insulin delivery (in Units) added together.'));
324324
}
325325
break;
326326

327327
case commonStats.carbs:
328328
if (days > 1) {
329-
annotations.push(t('**Avg. Daily Carbs**: All carb entries added together, then divided by the number of days in this view. Note, these entries come from either bolus wizard events, or Apple Health records.'));
329+
annotations.push(t('**Avg. Daily Carbs**: All carb entries added together, then divided by the number of days in this view for which we have carb data. Note, these entries come from either bolus wizard events, or Apple Health records.'));
330330
} else {
331331
annotations.push(t('**Total Carbs**: All carb entries from bolus wizard events or Apple Health records added together.'));
332332
}
@@ -385,11 +385,11 @@ export const getStatAnnotations = (data, type, opts = {}) => {
385385

386386
case commonStats.totalInsulin:
387387
if (days > 1) {
388-
annotations.push(t('**Total Insulin:** All basal and bolus insulin delivery (in Units) added together, divided by the number of days in this view'));
388+
annotations.push(t('**Total Insulin:** All basal and bolus insulin delivery (in Units) added together, divided by the number of days in this view for which we have insulin data'));
389389
} else {
390390
annotations.push(t('**Total Insulin:** All basal and bolus insulin delivery (in Units) added together'));
391391
}
392-
annotations.push(t('**How we calculate this:**\n\n**(%)** is the respective total of basal or bolus delivery divided by total insulin delivered for this time period.'));
392+
annotations.push(t('**How we calculate this:**\n\n**(%)** is the respective total of basal or bolus delivery divided by total insulin delivered for the time period for which we have insulin data.'));
393393
break;
394394

395395
default:

test/modules/print/BasicsPrintView.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ describe('BasicsPrintView', () => {
232232
sinon.assert.calledWithMatch(Renderer.renderCalendarSection, {
233233
title: {
234234
text: Renderer.sections.boluses.title,
235-
subText: '(days with no boluses have been excluded)',
235+
subText: '(days with no insulin data have been excluded)',
236236
},
237237
data: Renderer.aggregationsByDate.boluses.byDate,
238238
type: 'bolus',

test/utils/StatUtil.test.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,15 @@ describe('StatUtil', () => {
423423
});
424424
});
425425

426+
it('calculates insulin delivery using only data-populated days when viewing more than 1 day', () => {
427+
filterEndpoints(twoDayEndpoints);
428+
statUtil.activeDays = 7; // data only exists for 2 days; this should not impact the calculation
429+
expect(statUtil.getBasalBolusData()).to.eql({
430+
basal: 0.75,
431+
bolus: 7.5,
432+
});
433+
});
434+
426435
context('basal delivery overlaps endpoints', () => {
427436
it('should include the portion of delivery of a basal datum that overlaps the start endpoint', () => {
428437
statUtil.dataUtil.addData([basalDatumOverlappingStart], patientId);
@@ -482,6 +491,15 @@ describe('StatUtil', () => {
482491
total: 7,
483492
});
484493
});
494+
495+
it('calculates avg daily carbs using only data-populated days when viewing more than 1 day', () => {
496+
filterEndpoints(twoDayEndpoints);
497+
statUtil.activeDays = 7; // data only exists for 2 days; this should not impact the calculation
498+
expect(statUtil.getCarbsData()).to.eql({
499+
carbs: { grams: 21.5, exchanges: 1 },
500+
total: 7,
501+
});
502+
});
485503
});
486504

487505
describe('getCoefficientOfVariationData', () => {

test/utils/basics/data.test.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,6 @@ describe('basics data utils', () => {
589589
},
590590
bgPrefs: bgPrefs[MGDL_UNITS],
591591
timePrefs,
592-
query: { excludeDaysWithoutBolus: true },
593592
metaData: {
594593
devices: [
595594
{ id: 'deviceWithLabelId', label: 'Device With Label' },
@@ -691,7 +690,7 @@ describe('basics data utils', () => {
691690

692691
it('should add a note regarding excluded basics bolus days', () => {
693692
dataUtils.basicsText(patient, data, stats, aggregations);
694-
sinon.assert.calledWith(textUtilStub.buildTextLine, 'Days with no boluses have been excluded from bolus calculations');
693+
sinon.assert.calledWith(textUtilStub.buildTextLine, 'Days with no insulin data have been excluded from calculations');
695694
});
696695

697696
it('should build the basics stats section', () => {

test/utils/stat.test.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -872,7 +872,7 @@ describe('stat', () => {
872872

873873
it('should return annotations for `averageDailyDose` stat when viewing multiple days of data', () => {
874874
expect(stat.getStatAnnotations(data, commonStats.averageDailyDose, multiDayOpts)).to.have.ordered.members([
875-
'**Avg. Daily Insulin:** All basal and bolus insulin delivery (in Units) added together, divided by the number of days in this view.',
875+
'**Avg. Daily Insulin:** All basal and bolus insulin delivery (in Units) added together, divided by the number of days in this view for which we have insulin data.',
876876
]);
877877
});
878878
});
@@ -887,7 +887,7 @@ describe('stat', () => {
887887

888888
it('should return annotations for `carbs` stat when viewing multiple days of data', () => {
889889
expect(stat.getStatAnnotations(data, commonStats.carbs, multiDayOpts)).to.have.ordered.members([
890-
'**Avg. Daily Carbs**: All carb entries added together, then divided by the number of days in this view. Note, these entries come from either bolus wizard events, or Apple Health records.',
890+
'**Avg. Daily Carbs**: All carb entries added together, then divided by the number of days in this view for which we have carb data. Note, these entries come from either bolus wizard events, or Apple Health records.',
891891
'Derived from _**10**_ carb entries.',
892892
]);
893893
});
@@ -1033,14 +1033,14 @@ describe('stat', () => {
10331033
it('should return annotations for `totalInsulin` stat when viewing a single day of data', () => {
10341034
expect(stat.getStatAnnotations(data, commonStats.totalInsulin, singleDayOpts)).to.have.ordered.members([
10351035
'**Total Insulin:** All basal and bolus insulin delivery (in Units) added together',
1036-
'**How we calculate this:**\n\n**(%)** is the respective total of basal or bolus delivery divided by total insulin delivered for this time period.',
1036+
'**How we calculate this:**\n\n**(%)** is the respective total of basal or bolus delivery divided by total insulin delivered for the time period for which we have insulin data.',
10371037
]);
10381038
});
10391039

10401040
it('should return annotations for `totalInsulin` stat when viewing multiple days of data', () => {
10411041
expect(stat.getStatAnnotations(data, commonStats.totalInsulin, multiDayOpts)).to.have.ordered.members([
1042-
'**Total Insulin:** All basal and bolus insulin delivery (in Units) added together, divided by the number of days in this view',
1043-
'**How we calculate this:**\n\n**(%)** is the respective total of basal or bolus delivery divided by total insulin delivered for this time period.',
1042+
'**Total Insulin:** All basal and bolus insulin delivery (in Units) added together, divided by the number of days in this view for which we have insulin data',
1043+
'**How we calculate this:**\n\n**(%)** is the respective total of basal or bolus delivery divided by total insulin delivered for the time period for which we have insulin data.',
10441044
]);
10451045
});
10461046
});

0 commit comments

Comments
 (0)