@genspectrum/dashboard-components 0.6.18 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -12
- package/custom-elements.json +22 -22
- package/dist/assets/mutationOverTimeWorker-BOCXtKzd.js.map +1 -0
- package/dist/dashboard-components.js +301 -302
- package/dist/dashboard-components.js.map +1 -1
- package/dist/genspectrum-components.d.ts +60 -10
- package/dist/style.css +3 -2
- package/package.json +13 -4
- package/src/index.ts +1 -0
- package/src/operator/FetchInsertionsOperator.ts +2 -2
- package/src/operator/FetchSubstitutionsOrDeletionsOperator.ts +3 -3
- package/src/preact/dateRangeSelector/computeInitialValues.spec.ts +53 -38
- package/src/preact/dateRangeSelector/computeInitialValues.ts +17 -23
- package/src/preact/dateRangeSelector/date-range-selector.stories.tsx +46 -32
- package/src/preact/dateRangeSelector/date-range-selector.tsx +24 -26
- package/src/preact/dateRangeSelector/dateRangeOption.ts +65 -0
- package/src/preact/dateRangeSelector/selectableOptions.ts +17 -66
- package/src/preact/mutationComparison/fetchMutationData.spec.ts +3 -3
- package/src/preact/mutationComparison/getMutationComparisonTableData.spec.ts +11 -11
- package/src/preact/mutationComparison/getMutationComparisonTableData.ts +4 -4
- package/src/preact/mutationComparison/mutation-comparison-table.tsx +2 -2
- package/src/preact/mutationFilter/mutation-filter.tsx +27 -18
- package/src/preact/mutationFilter/parseAndValidateMutation.ts +4 -4
- package/src/preact/mutationFilter/parseMutation.spec.ts +17 -17
- package/src/preact/mutations/getInsertionsTableData.spec.ts +3 -3
- package/src/preact/mutations/getMutationsGridData.spec.ts +9 -9
- package/src/preact/mutations/getMutationsTableData.spec.ts +7 -7
- package/src/preact/mutations/mutations-insertions-table.tsx +3 -3
- package/src/preact/mutations/mutations-table.tsx +3 -3
- package/src/preact/mutationsOverTime/MutationOverTimeData.ts +20 -0
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutationsByDay.ts +45686 -0
- package/src/preact/mutationsOverTime/__mockData__/byWeek.ts +58989 -0
- package/src/preact/mutationsOverTime/__mockData__/defaultMockData.ts +103991 -0
- package/src/preact/mutationsOverTime/__mockData__/mockConversion.ts +54 -0
- package/src/preact/mutationsOverTime/__mockData__/showsMessageWhenTooManyMutations.ts +63690 -0
- package/src/preact/mutationsOverTime/getFilteredMutationsOverTime.spec.ts +177 -161
- package/src/preact/mutationsOverTime/getFilteredMutationsOverTimeData.ts +17 -59
- package/src/preact/mutationsOverTime/mutationOverTimeWorker.mock.ts +27 -0
- package/src/preact/mutationsOverTime/mutationOverTimeWorker.ts +29 -0
- package/src/preact/mutationsOverTime/mutations-over-time-grid.tsx +13 -14
- package/src/preact/mutationsOverTime/mutations-over-time.stories.tsx +9 -334
- package/src/preact/mutationsOverTime/mutations-over-time.tsx +59 -54
- package/src/preact/numberSequencesOverTime/getNumberOfSequencesOverTimeTableData.ts +3 -3
- package/src/preact/prevalenceOverTime/getPrevalenceOverTimeTableData.spec.ts +5 -5
- package/src/preact/prevalenceOverTime/prevalence-over-time-bubble-chart.tsx +1 -1
- package/src/preact/relativeGrowthAdvantage/relative-growth-advantage-chart.tsx +2 -2
- package/src/preact/shared/sort/sortInsertions.spec.ts +11 -11
- package/src/preact/shared/sort/sortInsertions.ts +2 -2
- package/src/preact/shared/sort/sortSubstitutionsAndDeletions.spec.ts +13 -13
- package/src/preact/shared/sort/sortSubstitutionsAndDeletions.ts +7 -4
- package/src/preact/webWorkers/useWebWorker.ts +51 -0
- package/src/preact/webWorkers/workerFunction.ts +14 -0
- package/src/query/queryAggregatedDataOverTime.ts +3 -3
- package/src/query/queryMutationsOverTime.spec.ts +272 -51
- package/src/query/queryMutationsOverTime.ts +114 -47
- package/src/query/queryPrevalenceOverTime.ts +2 -2
- package/src/query/queryRelativeGrowthAdvantage.ts +3 -3
- package/src/types.ts +25 -5
- package/src/utils/map2d.spec.ts +79 -12
- package/src/utils/map2d.ts +25 -5
- package/src/utils/mutations.spec.ts +20 -20
- package/src/utils/mutations.ts +80 -17
- package/src/utils/sort.ts +5 -2
- package/src/utils/temporal.spec.ts +27 -24
- package/src/utils/{temporal.ts → temporalClass.ts} +170 -72
- package/src/utils/temporalTestHelpers.ts +3 -3
- package/src/web-components/input/gs-date-range-selector.stories.ts +16 -28
- package/src/web-components/input/gs-date-range-selector.tsx +17 -32
- package/src/web-components/introduction.mdx +46 -0
- package/src/web-components/visualization/gs-mutations-over-time.stories.ts +6 -699
- package/src/web-components/visualization/gs-mutations-over-time.tsx +2 -2
- package/standalone-bundle/dashboard-components.js +12011 -12778
- package/standalone-bundle/dashboard-components.js.map +1 -1
- package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_01.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_02.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_03.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_04.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_05.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_06.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_07.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_20_01_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_21_01_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_22_01_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_23_01_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_24_01_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_25_01_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_26_01_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_byDay.json +0 -38
- package/src/preact/mutationsOverTime/__mockData__/aggregated_byWeek.json +0 -122
- package/src/preact/mutationsOverTime/__mockData__/aggregated_date.json +0 -642
- package/src/preact/mutationsOverTime/__mockData__/aggregated_tooManyMutations.json +0 -1470
- package/src/preact/mutationsOverTime/__mockData__/aggregated_tooManyMutations_total.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_week3_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_week4_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_week5_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_week6_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_20_01_2024.json +0 -6778
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_21_01_2024.json +0 -7129
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_22_01_2024.json +0 -4681
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_23_01_2024.json +0 -10738
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_24_01_2024.json +0 -11710
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_25_01_2024.json +0 -11557
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_26_01_2024.json +0 -8596
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_byDayOverall.json +0 -4726
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_01.json +0 -1747
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_02.json +0 -1774
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_03.json +0 -1819
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_04.json +0 -1864
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_05.json +0 -1927
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_06.json +0 -1864
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_07.json +0 -9
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_byMonthOverall.json +0 -11143
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_byWeekOverall.json +0 -9154
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_tooManyMutations.json +0 -16453
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_week3_2024.json +0 -8812
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_week4_2024.json +0 -9730
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_week5_2024.json +0 -9865
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_week6_2024.json +0 -11314
|
@@ -4,7 +4,7 @@ import { queryMutationsOverTimeData } from './queryMutationsOverTime';
|
|
|
4
4
|
import { DUMMY_LAPIS_URL, lapisRequestMocks } from '../../vitest.setup';
|
|
5
5
|
|
|
6
6
|
describe('queryMutationsOverTime', () => {
|
|
7
|
-
it('should fetch for a filter without date', async () => {
|
|
7
|
+
it('should fetch for a filter without date and sort by mutation and date', async () => {
|
|
8
8
|
const lapisFilter = { field1: 'value1', field2: 'value2' };
|
|
9
9
|
const dateField = 'dateField';
|
|
10
10
|
|
|
@@ -76,33 +76,79 @@ describe('queryMutationsOverTime', () => {
|
|
|
76
76
|
},
|
|
77
77
|
response: { data: [getSomeTestMutation(0.3, 3)] },
|
|
78
78
|
},
|
|
79
|
+
{
|
|
80
|
+
body: {
|
|
81
|
+
...lapisFilter,
|
|
82
|
+
dateFieldFrom: '2023-01-01',
|
|
83
|
+
dateFieldTo: '2023-01-03',
|
|
84
|
+
minProportion: 0.001,
|
|
85
|
+
},
|
|
86
|
+
response: {
|
|
87
|
+
data: [getSomeTestMutation(0.21, 6), getSomeOtherTestMutation(0.22, 4)],
|
|
88
|
+
},
|
|
89
|
+
},
|
|
79
90
|
],
|
|
80
91
|
'nucleotide',
|
|
81
92
|
);
|
|
82
93
|
|
|
83
|
-
const
|
|
94
|
+
const { mutationOverTimeData, overallMutationData } = await queryMutationsOverTimeData({
|
|
95
|
+
lapisFilter,
|
|
96
|
+
sequenceType: 'nucleotide',
|
|
97
|
+
lapis: DUMMY_LAPIS_URL,
|
|
98
|
+
lapisDateField: dateField,
|
|
99
|
+
granularity: 'day',
|
|
100
|
+
});
|
|
84
101
|
|
|
85
|
-
expect(
|
|
86
|
-
[
|
|
87
|
-
{ proportion: 0.1, count: 1, totalCount: 11 },
|
|
88
|
-
{ proportion: 0.2, count: 2, totalCount: 12 },
|
|
89
|
-
{ proportion: 0.3, count: 3, totalCount: 13 },
|
|
90
|
-
],
|
|
102
|
+
expect(mutationOverTimeData.getAsArray({ count: 0, proportion: 0, totalCount: 0 })).to.deep.equal([
|
|
91
103
|
[
|
|
92
104
|
{ proportion: 0.4, count: 4, totalCount: 11 },
|
|
93
105
|
{ proportion: 0, count: 0, totalCount: 0 },
|
|
94
106
|
{ proportion: 0, count: 0, totalCount: 0 },
|
|
95
107
|
],
|
|
108
|
+
[
|
|
109
|
+
{ proportion: 0.1, count: 1, totalCount: 11 },
|
|
110
|
+
{ proportion: 0.2, count: 2, totalCount: 12 },
|
|
111
|
+
{ proportion: 0.3, count: 3, totalCount: 13 },
|
|
112
|
+
],
|
|
96
113
|
]);
|
|
97
114
|
|
|
98
|
-
const sequences =
|
|
99
|
-
expect(sequences[0].code).toBe('
|
|
100
|
-
expect(sequences[1].code).toBe('
|
|
115
|
+
const sequences = mutationOverTimeData.getFirstAxisKeys();
|
|
116
|
+
expect(sequences[0].code).toBe('otherSequenceName:G234C');
|
|
117
|
+
expect(sequences[1].code).toBe('sequenceName:A123T');
|
|
118
|
+
|
|
119
|
+
const dates = mutationOverTimeData.getSecondAxisKeys();
|
|
120
|
+
expect(dates[0].dateString).toBe('2023-01-01');
|
|
121
|
+
expect(dates[1].dateString).toBe('2023-01-02');
|
|
122
|
+
expect(dates[2].dateString).toBe('2023-01-03');
|
|
101
123
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
124
|
+
expect(overallMutationData).to.deep.equal([
|
|
125
|
+
{
|
|
126
|
+
type: 'substitution',
|
|
127
|
+
mutation: {
|
|
128
|
+
valueAtReference: 'G',
|
|
129
|
+
substitutionValue: 'C',
|
|
130
|
+
position: 234,
|
|
131
|
+
segment: 'otherSequenceName',
|
|
132
|
+
code: 'otherSequenceName:G234C',
|
|
133
|
+
type: 'substitution',
|
|
134
|
+
},
|
|
135
|
+
count: 4,
|
|
136
|
+
proportion: 0.22,
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
type: 'substitution',
|
|
140
|
+
mutation: {
|
|
141
|
+
valueAtReference: 'A',
|
|
142
|
+
substitutionValue: 'T',
|
|
143
|
+
position: 123,
|
|
144
|
+
segment: 'sequenceName',
|
|
145
|
+
code: 'sequenceName:A123T',
|
|
146
|
+
type: 'substitution',
|
|
147
|
+
},
|
|
148
|
+
count: 6,
|
|
149
|
+
proportion: 0.21,
|
|
150
|
+
},
|
|
151
|
+
]);
|
|
106
152
|
});
|
|
107
153
|
|
|
108
154
|
it('should fetch for dates with no mutations', async () => {
|
|
@@ -177,33 +223,54 @@ describe('queryMutationsOverTime', () => {
|
|
|
177
223
|
},
|
|
178
224
|
response: { data: [getSomeTestMutation(0.3, 3)] },
|
|
179
225
|
},
|
|
226
|
+
{
|
|
227
|
+
body: {
|
|
228
|
+
...lapisFilter,
|
|
229
|
+
dateFieldFrom: '2023-01-01',
|
|
230
|
+
dateFieldTo: '2023-01-03',
|
|
231
|
+
minProportion: 0.001,
|
|
232
|
+
},
|
|
233
|
+
response: {
|
|
234
|
+
data: [
|
|
235
|
+
getSomeTestMutation(0.1, 1),
|
|
236
|
+
getSomeTestMutation(0.3, 3),
|
|
237
|
+
getSomeOtherTestMutation(0.4, 4),
|
|
238
|
+
],
|
|
239
|
+
},
|
|
240
|
+
},
|
|
180
241
|
],
|
|
181
242
|
'nucleotide',
|
|
182
243
|
);
|
|
183
244
|
|
|
184
|
-
const
|
|
245
|
+
const { mutationOverTimeData } = await queryMutationsOverTimeData({
|
|
246
|
+
lapisFilter,
|
|
247
|
+
sequenceType: 'nucleotide',
|
|
248
|
+
lapis: DUMMY_LAPIS_URL,
|
|
249
|
+
lapisDateField: dateField,
|
|
250
|
+
granularity: 'day',
|
|
251
|
+
});
|
|
185
252
|
|
|
186
|
-
expect(
|
|
253
|
+
expect(mutationOverTimeData.getAsArray({ count: 0, proportion: 0, totalCount: 0 })).to.deep.equal([
|
|
187
254
|
[
|
|
188
|
-
{ proportion: 0.
|
|
189
|
-
{ proportion: 0
|
|
255
|
+
{ proportion: 0.4, count: 4, totalCount: 11 },
|
|
256
|
+
{ proportion: 0, count: 0, totalCount: 0 },
|
|
190
257
|
{ proportion: 0, count: 0, totalCount: 0 },
|
|
191
258
|
],
|
|
192
259
|
[
|
|
193
|
-
{ proportion: 0.
|
|
194
|
-
{ proportion: 0, count: 0, totalCount: 0 },
|
|
260
|
+
{ proportion: 0.1, count: 1, totalCount: 11 },
|
|
195
261
|
{ proportion: 0, count: 0, totalCount: 0 },
|
|
262
|
+
{ proportion: 0.3, count: 3, totalCount: 13 },
|
|
196
263
|
],
|
|
197
264
|
]);
|
|
198
265
|
|
|
199
|
-
const sequences =
|
|
200
|
-
expect(sequences[0].code).toBe('
|
|
201
|
-
expect(sequences[1].code).toBe('
|
|
266
|
+
const sequences = mutationOverTimeData.getFirstAxisKeys();
|
|
267
|
+
expect(sequences[0].code).toBe('otherSequenceName:G234C');
|
|
268
|
+
expect(sequences[1].code).toBe('sequenceName:A123T');
|
|
202
269
|
|
|
203
|
-
const dates =
|
|
204
|
-
expect(dates[0].
|
|
205
|
-
expect(dates[1].
|
|
206
|
-
expect(dates[2].
|
|
270
|
+
const dates = mutationOverTimeData.getSecondAxisKeys();
|
|
271
|
+
expect(dates[0].dateString).toBe('2023-01-01');
|
|
272
|
+
expect(dates[1].dateString).toBe('2023-01-02');
|
|
273
|
+
expect(dates[2].dateString).toBe('2023-01-03');
|
|
207
274
|
});
|
|
208
275
|
|
|
209
276
|
it('should return empty map when no mutations are found', async () => {
|
|
@@ -278,15 +345,32 @@ describe('queryMutationsOverTime', () => {
|
|
|
278
345
|
},
|
|
279
346
|
response: { data: [] },
|
|
280
347
|
},
|
|
348
|
+
{
|
|
349
|
+
body: {
|
|
350
|
+
...lapisFilter,
|
|
351
|
+
dateFieldFrom: '2023-01-01',
|
|
352
|
+
dateFieldTo: '2023-01-03',
|
|
353
|
+
minProportion: 0.001,
|
|
354
|
+
},
|
|
355
|
+
response: {
|
|
356
|
+
data: [],
|
|
357
|
+
},
|
|
358
|
+
},
|
|
281
359
|
],
|
|
282
360
|
'nucleotide',
|
|
283
361
|
);
|
|
284
362
|
|
|
285
|
-
const
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
363
|
+
const { mutationOverTimeData } = await queryMutationsOverTimeData({
|
|
364
|
+
lapisFilter,
|
|
365
|
+
sequenceType: 'nucleotide',
|
|
366
|
+
lapis: DUMMY_LAPIS_URL,
|
|
367
|
+
lapisDateField: dateField,
|
|
368
|
+
granularity: 'day',
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
expect(mutationOverTimeData.getAsArray({ count: 0, proportion: 0, totalCount: 0 })).to.deep.equal([]);
|
|
372
|
+
expect(mutationOverTimeData.getFirstAxisKeys()).to.deep.equal([]);
|
|
373
|
+
expect(mutationOverTimeData.getSecondAxisKeys()).to.deep.equal([]);
|
|
290
374
|
});
|
|
291
375
|
|
|
292
376
|
it('should use dateFrom from filter', async () => {
|
|
@@ -343,25 +427,42 @@ describe('queryMutationsOverTime', () => {
|
|
|
343
427
|
},
|
|
344
428
|
response: { data: [getSomeTestMutation(0.3, 3)] },
|
|
345
429
|
},
|
|
430
|
+
{
|
|
431
|
+
body: {
|
|
432
|
+
...lapisFilter,
|
|
433
|
+
dateFieldFrom: '2023-01-02',
|
|
434
|
+
dateFieldTo: '2023-01-03',
|
|
435
|
+
minProportion: 0.001,
|
|
436
|
+
},
|
|
437
|
+
response: {
|
|
438
|
+
data: [getSomeTestMutation(0.2, 2), getSomeTestMutation(0.3, 3)],
|
|
439
|
+
},
|
|
440
|
+
},
|
|
346
441
|
],
|
|
347
442
|
'nucleotide',
|
|
348
443
|
);
|
|
349
444
|
|
|
350
|
-
const
|
|
445
|
+
const { mutationOverTimeData } = await queryMutationsOverTimeData({
|
|
446
|
+
lapisFilter,
|
|
447
|
+
sequenceType: 'nucleotide',
|
|
448
|
+
lapis: DUMMY_LAPIS_URL,
|
|
449
|
+
lapisDateField: dateField,
|
|
450
|
+
granularity: 'day',
|
|
451
|
+
});
|
|
351
452
|
|
|
352
|
-
expect(
|
|
453
|
+
expect(mutationOverTimeData.getAsArray({ count: 0, proportion: 0, totalCount: 0 })).to.deep.equal([
|
|
353
454
|
[
|
|
354
455
|
{ proportion: 0.2, count: 2, totalCount: 11 },
|
|
355
456
|
{ proportion: 0.3, count: 3, totalCount: 12 },
|
|
356
457
|
],
|
|
357
458
|
]);
|
|
358
459
|
|
|
359
|
-
const sequences =
|
|
460
|
+
const sequences = mutationOverTimeData.getFirstAxisKeys();
|
|
360
461
|
expect(sequences[0].code).toBe('sequenceName:A123T');
|
|
361
462
|
|
|
362
|
-
const dates =
|
|
363
|
-
expect(dates[0].
|
|
364
|
-
expect(dates[1].
|
|
463
|
+
const dates = mutationOverTimeData.getSecondAxisKeys();
|
|
464
|
+
expect(dates[0].dateString).toBe('2023-01-02');
|
|
465
|
+
expect(dates[1].dateString).toBe('2023-01-03');
|
|
365
466
|
});
|
|
366
467
|
|
|
367
468
|
it('should use dateTo from filter', async () => {
|
|
@@ -418,25 +519,42 @@ describe('queryMutationsOverTime', () => {
|
|
|
418
519
|
},
|
|
419
520
|
response: { data: [getSomeTestMutation(0.2, 2)] },
|
|
420
521
|
},
|
|
522
|
+
{
|
|
523
|
+
body: {
|
|
524
|
+
...lapisFilter,
|
|
525
|
+
dateFieldFrom: '2023-01-01',
|
|
526
|
+
dateFieldTo: '2023-01-02',
|
|
527
|
+
minProportion: 0.001,
|
|
528
|
+
},
|
|
529
|
+
response: {
|
|
530
|
+
data: [getSomeTestMutation(0.1, 1), getSomeTestMutation(0.2, 2)],
|
|
531
|
+
},
|
|
532
|
+
},
|
|
421
533
|
],
|
|
422
534
|
'nucleotide',
|
|
423
535
|
);
|
|
424
536
|
|
|
425
|
-
const
|
|
537
|
+
const { mutationOverTimeData } = await queryMutationsOverTimeData({
|
|
538
|
+
lapisFilter,
|
|
539
|
+
sequenceType: 'nucleotide',
|
|
540
|
+
lapis: DUMMY_LAPIS_URL,
|
|
541
|
+
lapisDateField: dateField,
|
|
542
|
+
granularity: 'day',
|
|
543
|
+
});
|
|
426
544
|
|
|
427
|
-
expect(
|
|
545
|
+
expect(mutationOverTimeData.getAsArray({ count: 0, proportion: 0, totalCount: 0 })).to.deep.equal([
|
|
428
546
|
[
|
|
429
547
|
{ proportion: 0.1, count: 1, totalCount: 11 },
|
|
430
548
|
{ proportion: 0.2, count: 2, totalCount: 12 },
|
|
431
549
|
],
|
|
432
550
|
]);
|
|
433
551
|
|
|
434
|
-
const sequences =
|
|
552
|
+
const sequences = mutationOverTimeData.getFirstAxisKeys();
|
|
435
553
|
expect(sequences[0].code).toBe('sequenceName:A123T');
|
|
436
554
|
|
|
437
|
-
const dates =
|
|
438
|
-
expect(dates[0].
|
|
439
|
-
expect(dates[1].
|
|
555
|
+
const dates = mutationOverTimeData.getSecondAxisKeys();
|
|
556
|
+
expect(dates[0].dateString).toBe('2023-01-01');
|
|
557
|
+
expect(dates[1].dateString).toBe('2023-01-02');
|
|
440
558
|
});
|
|
441
559
|
|
|
442
560
|
it('should use date from filter', async () => {
|
|
@@ -479,9 +597,15 @@ describe('queryMutationsOverTime', () => {
|
|
|
479
597
|
'nucleotide',
|
|
480
598
|
);
|
|
481
599
|
|
|
482
|
-
const
|
|
600
|
+
const { mutationOverTimeData } = await queryMutationsOverTimeData({
|
|
601
|
+
lapisFilter,
|
|
602
|
+
sequenceType: 'nucleotide',
|
|
603
|
+
lapis: DUMMY_LAPIS_URL,
|
|
604
|
+
lapisDateField: dateField,
|
|
605
|
+
granularity: 'day',
|
|
606
|
+
});
|
|
483
607
|
|
|
484
|
-
expect(
|
|
608
|
+
expect(mutationOverTimeData.getAsArray({ count: 0, proportion: 0, totalCount: 0 })).to.deep.equal([
|
|
485
609
|
[
|
|
486
610
|
{
|
|
487
611
|
proportion: 0.2,
|
|
@@ -491,11 +615,108 @@ describe('queryMutationsOverTime', () => {
|
|
|
491
615
|
],
|
|
492
616
|
]);
|
|
493
617
|
|
|
494
|
-
const sequences =
|
|
618
|
+
const sequences = mutationOverTimeData.getFirstAxisKeys();
|
|
495
619
|
expect(sequences[0].code).toBe('sequenceName:A123T');
|
|
496
620
|
|
|
497
|
-
const dates =
|
|
498
|
-
expect(dates[0].
|
|
621
|
+
const dates = mutationOverTimeData.getSecondAxisKeys();
|
|
622
|
+
expect(dates[0].dateString).toBe('2023-01-02');
|
|
623
|
+
});
|
|
624
|
+
|
|
625
|
+
it('should fetch data including the first and last day of the granularity', async () => {
|
|
626
|
+
const lapisFilter = { field1: 'value1', field2: 'value2' };
|
|
627
|
+
const dateField = 'dateField';
|
|
628
|
+
|
|
629
|
+
lapisRequestMocks.multipleAggregated([
|
|
630
|
+
{
|
|
631
|
+
body: { ...lapisFilter, fields: [dateField] },
|
|
632
|
+
response: {
|
|
633
|
+
data: [
|
|
634
|
+
{ count: 1, [dateField]: '2023-01-05' },
|
|
635
|
+
{ count: 2, [dateField]: '2023-02-15' },
|
|
636
|
+
],
|
|
637
|
+
},
|
|
638
|
+
},
|
|
639
|
+
{
|
|
640
|
+
body: {
|
|
641
|
+
...lapisFilter,
|
|
642
|
+
dateFieldFrom: '2023-01-01',
|
|
643
|
+
dateFieldTo: '2023-01-31',
|
|
644
|
+
fields: [],
|
|
645
|
+
},
|
|
646
|
+
response: { data: [{ count: 11 }] },
|
|
647
|
+
},
|
|
648
|
+
{
|
|
649
|
+
body: {
|
|
650
|
+
...lapisFilter,
|
|
651
|
+
dateFieldFrom: '2023-02-01',
|
|
652
|
+
dateFieldTo: '2023-02-28',
|
|
653
|
+
fields: [],
|
|
654
|
+
},
|
|
655
|
+
response: { data: [{ count: 12 }] },
|
|
656
|
+
},
|
|
657
|
+
]);
|
|
658
|
+
|
|
659
|
+
lapisRequestMocks.multipleMutations(
|
|
660
|
+
[
|
|
661
|
+
{
|
|
662
|
+
body: {
|
|
663
|
+
...lapisFilter,
|
|
664
|
+
dateFieldFrom: '2023-01-01',
|
|
665
|
+
dateFieldTo: '2023-01-31',
|
|
666
|
+
minProportion: 0.001,
|
|
667
|
+
},
|
|
668
|
+
response: { data: [getSomeTestMutation(0.1, 1), getSomeOtherTestMutation(0.4, 4)] },
|
|
669
|
+
},
|
|
670
|
+
{
|
|
671
|
+
body: {
|
|
672
|
+
...lapisFilter,
|
|
673
|
+
dateFieldFrom: '2023-02-01',
|
|
674
|
+
dateFieldTo: '2023-02-28',
|
|
675
|
+
minProportion: 0.001,
|
|
676
|
+
},
|
|
677
|
+
response: { data: [getSomeTestMutation(0.2, 2)] },
|
|
678
|
+
},
|
|
679
|
+
{
|
|
680
|
+
body: {
|
|
681
|
+
...lapisFilter,
|
|
682
|
+
dateFieldFrom: '2023-01-01',
|
|
683
|
+
dateFieldTo: '2023-02-28',
|
|
684
|
+
minProportion: 0.001,
|
|
685
|
+
},
|
|
686
|
+
response: {
|
|
687
|
+
data: [getSomeTestMutation(0.21, 6), getSomeOtherTestMutation(0.22, 4)],
|
|
688
|
+
},
|
|
689
|
+
},
|
|
690
|
+
],
|
|
691
|
+
'nucleotide',
|
|
692
|
+
);
|
|
693
|
+
|
|
694
|
+
const { mutationOverTimeData } = await queryMutationsOverTimeData({
|
|
695
|
+
lapisFilter,
|
|
696
|
+
sequenceType: 'nucleotide',
|
|
697
|
+
lapis: DUMMY_LAPIS_URL,
|
|
698
|
+
lapisDateField: dateField,
|
|
699
|
+
granularity: 'month',
|
|
700
|
+
});
|
|
701
|
+
|
|
702
|
+
expect(mutationOverTimeData.getAsArray({ count: 0, proportion: 0, totalCount: 0 })).to.deep.equal([
|
|
703
|
+
[
|
|
704
|
+
{ proportion: 0.4, count: 4, totalCount: 11 },
|
|
705
|
+
{ proportion: 0, count: 0, totalCount: 0 },
|
|
706
|
+
],
|
|
707
|
+
[
|
|
708
|
+
{ proportion: 0.1, count: 1, totalCount: 11 },
|
|
709
|
+
{ proportion: 0.2, count: 2, totalCount: 12 },
|
|
710
|
+
],
|
|
711
|
+
]);
|
|
712
|
+
|
|
713
|
+
const sequences = mutationOverTimeData.getFirstAxisKeys();
|
|
714
|
+
expect(sequences[0].code).toBe('otherSequenceName:G234C');
|
|
715
|
+
expect(sequences[1].code).toBe('sequenceName:A123T');
|
|
716
|
+
|
|
717
|
+
const dates = mutationOverTimeData.getSecondAxisKeys();
|
|
718
|
+
expect(dates[0].dateString).toBe('2023-01');
|
|
719
|
+
expect(dates[1].dateString).toBe('2023-02');
|
|
499
720
|
});
|
|
500
721
|
|
|
501
722
|
function getSomeTestMutation(proportion: number, count: number) {
|
|
@@ -512,7 +733,7 @@ describe('queryMutationsOverTime', () => {
|
|
|
512
733
|
|
|
513
734
|
function getSomeOtherTestMutation(proportion: number, count: number) {
|
|
514
735
|
return {
|
|
515
|
-
mutation: 'otherSequenceName:
|
|
736
|
+
mutation: 'otherSequenceName:G234C',
|
|
516
737
|
proportion,
|
|
517
738
|
count,
|
|
518
739
|
sequenceName: 'otherSequenceName',
|
|
@@ -6,54 +6,92 @@ import { MapOperator } from '../operator/MapOperator';
|
|
|
6
6
|
import { RenameFieldOperator } from '../operator/RenameFieldOperator';
|
|
7
7
|
import { SortOperator } from '../operator/SortOperator';
|
|
8
8
|
import { UserFacingError } from '../preact/components/error-display';
|
|
9
|
+
import { BaseMutationOverTimeDataMap } from '../preact/mutationsOverTime/MutationOverTimeData';
|
|
10
|
+
import { sortSubstitutionsAndDeletions } from '../preact/shared/sort/sortSubstitutionsAndDeletions';
|
|
9
11
|
import {
|
|
12
|
+
type DeletionEntry,
|
|
10
13
|
type LapisFilter,
|
|
11
14
|
type SequenceType,
|
|
15
|
+
type SubstitutionEntry,
|
|
12
16
|
type SubstitutionOrDeletionEntry,
|
|
13
17
|
type TemporalGranularity,
|
|
14
18
|
} from '../types';
|
|
15
|
-
import {
|
|
16
|
-
import { type Deletion, type Substitution } from '../utils/mutations';
|
|
19
|
+
import { type Map2d } from '../utils/map2d';
|
|
17
20
|
import {
|
|
21
|
+
type Deletion,
|
|
22
|
+
type DeletionClass,
|
|
23
|
+
type Substitution,
|
|
24
|
+
type SubstitutionClass,
|
|
25
|
+
toSubstitutionOrDeletion,
|
|
26
|
+
} from '../utils/mutations';
|
|
27
|
+
import {
|
|
28
|
+
compareTemporal,
|
|
18
29
|
dateRangeCompare,
|
|
19
30
|
generateAllInRange,
|
|
20
31
|
getMinMaxTemporal,
|
|
21
32
|
parseDateStringToTemporal,
|
|
22
33
|
type Temporal,
|
|
23
|
-
|
|
34
|
+
type TemporalClass,
|
|
35
|
+
toTemporal,
|
|
36
|
+
} from '../utils/temporalClass';
|
|
24
37
|
|
|
25
38
|
export type MutationOverTimeData = {
|
|
26
|
-
date:
|
|
39
|
+
date: TemporalClass;
|
|
27
40
|
mutations: SubstitutionOrDeletionEntry[];
|
|
28
41
|
totalCount: number;
|
|
29
42
|
};
|
|
30
43
|
|
|
31
44
|
export type MutationOverTimeMutationValue = { proportion: number; count: number; totalCount: number };
|
|
32
45
|
export type MutationOverTimeDataGroupedByMutation = Map2d<
|
|
33
|
-
|
|
34
|
-
|
|
46
|
+
SubstitutionClass | DeletionClass,
|
|
47
|
+
TemporalClass,
|
|
35
48
|
MutationOverTimeMutationValue
|
|
36
49
|
>;
|
|
37
50
|
|
|
38
51
|
const MAX_NUMBER_OF_GRID_COLUMNS = 200;
|
|
39
52
|
|
|
40
|
-
export async function queryOverallMutationData(
|
|
41
|
-
lapisFilter
|
|
42
|
-
sequenceType
|
|
43
|
-
lapis
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
53
|
+
export async function queryOverallMutationData({
|
|
54
|
+
lapisFilter,
|
|
55
|
+
sequenceType,
|
|
56
|
+
lapis,
|
|
57
|
+
granularity,
|
|
58
|
+
lapisDateField,
|
|
59
|
+
signal,
|
|
60
|
+
}: {
|
|
61
|
+
lapisFilter: LapisFilter;
|
|
62
|
+
sequenceType: SequenceType;
|
|
63
|
+
lapis: string;
|
|
64
|
+
granularity: TemporalGranularity;
|
|
65
|
+
lapisDateField: string;
|
|
66
|
+
signal?: AbortSignal;
|
|
67
|
+
}) {
|
|
68
|
+
const allDates = await getDatesInDataset(lapisFilter, lapis, granularity, lapisDateField, signal);
|
|
69
|
+
const filter = {
|
|
70
|
+
...lapisFilter,
|
|
71
|
+
[`${lapisDateField}From`]: allDates[0].firstDay.toString(),
|
|
72
|
+
[`${lapisDateField}To`]: allDates[allDates.length - 1].lastDay.toString(),
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
return fetchAndPrepareSubstitutionsOrDeletions(filter, sequenceType).evaluate(lapis, signal);
|
|
47
76
|
}
|
|
48
77
|
|
|
49
|
-
export
|
|
50
|
-
lapisFilter: LapisFilter
|
|
51
|
-
sequenceType: SequenceType
|
|
52
|
-
lapis: string
|
|
53
|
-
lapisDateField: string
|
|
54
|
-
granularity: TemporalGranularity
|
|
55
|
-
signal?: AbortSignal
|
|
56
|
-
|
|
78
|
+
export type MutationOverTimeQuery = {
|
|
79
|
+
lapisFilter: LapisFilter;
|
|
80
|
+
sequenceType: SequenceType;
|
|
81
|
+
lapis: string;
|
|
82
|
+
lapisDateField: string;
|
|
83
|
+
granularity: TemporalGranularity;
|
|
84
|
+
signal?: AbortSignal;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export async function queryMutationsOverTimeData({
|
|
88
|
+
lapisFilter,
|
|
89
|
+
sequenceType,
|
|
90
|
+
lapis,
|
|
91
|
+
lapisDateField,
|
|
92
|
+
granularity,
|
|
93
|
+
signal,
|
|
94
|
+
}: MutationOverTimeQuery) {
|
|
57
95
|
const allDates = await getDatesInDataset(lapisFilter, lapis, granularity, lapisDateField, signal);
|
|
58
96
|
|
|
59
97
|
if (allDates.length > MAX_NUMBER_OF_GRID_COLUMNS) {
|
|
@@ -86,7 +124,20 @@ export async function queryMutationsOverTimeData(
|
|
|
86
124
|
|
|
87
125
|
const data = await Promise.all(subQueries);
|
|
88
126
|
|
|
89
|
-
|
|
127
|
+
const overallMutationsData = (
|
|
128
|
+
await queryOverallMutationData({
|
|
129
|
+
lapisFilter,
|
|
130
|
+
sequenceType,
|
|
131
|
+
lapis,
|
|
132
|
+
lapisDateField,
|
|
133
|
+
granularity,
|
|
134
|
+
})
|
|
135
|
+
).content;
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
mutationOverTimeData: groupByMutation(data, overallMutationsData),
|
|
139
|
+
overallMutationData: overallMutationsData,
|
|
140
|
+
};
|
|
90
141
|
}
|
|
91
142
|
|
|
92
143
|
async function getDatesInDataset(
|
|
@@ -156,39 +207,55 @@ function fetchAndPrepareSubstitutionsOrDeletions(filter: LapisFilter, sequenceTy
|
|
|
156
207
|
return new FetchSubstitutionsOrDeletionsOperator(filter, sequenceType, 0.001);
|
|
157
208
|
}
|
|
158
209
|
|
|
159
|
-
export function
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
(date) => date.toString(),
|
|
163
|
-
);
|
|
210
|
+
export function serializeSubstitutionOrDeletion(mutation: Substitution | Deletion) {
|
|
211
|
+
return mutation.code;
|
|
212
|
+
}
|
|
164
213
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
214
|
+
export function serializeTemporal(date: Temporal) {
|
|
215
|
+
return date.dateString;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export function groupByMutation(
|
|
219
|
+
data: MutationOverTimeData[],
|
|
220
|
+
overallMutationData: (SubstitutionEntry | DeletionEntry)[],
|
|
221
|
+
) {
|
|
222
|
+
const dataArray = new BaseMutationOverTimeDataMap();
|
|
223
|
+
|
|
224
|
+
const allDates = data.map((mutationData) => mutationData.date);
|
|
225
|
+
|
|
226
|
+
const sortedOverallMutationData = overallMutationData
|
|
227
|
+
.sort((a, b) => sortSubstitutionsAndDeletions(a.mutation, b.mutation))
|
|
228
|
+
.map((entry) => {
|
|
229
|
+
return toSubstitutionOrDeletion(entry.mutation);
|
|
230
|
+
});
|
|
231
|
+
const sortedDates = allDates.sort((a, b) => compareTemporal(a, b)).map((date) => toTemporal(date));
|
|
232
|
+
|
|
233
|
+
sortedOverallMutationData.forEach((mutationData) => {
|
|
234
|
+
sortedDates.forEach((date) => {
|
|
235
|
+
dataArray.set(mutationData, date, {
|
|
236
|
+
count: 0,
|
|
237
|
+
proportion: 0,
|
|
238
|
+
totalCount: 0,
|
|
171
239
|
});
|
|
172
240
|
});
|
|
173
241
|
});
|
|
174
242
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
243
|
+
data.forEach((mutationData) => {
|
|
244
|
+
mutationData.mutations.forEach((mutationEntry) => {
|
|
245
|
+
const mutation = toSubstitutionOrDeletion(mutationEntry.mutation);
|
|
246
|
+
const date = toTemporal(mutationData.date);
|
|
179
247
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
data.forEach((mutationData) => {
|
|
187
|
-
if (mutationData.mutations.length === 0) {
|
|
188
|
-
dataArray.set(someMutation, mutationData.date, { count: 0, proportion: 0, totalCount: 0 });
|
|
248
|
+
if (dataArray.get(mutation, date) !== undefined) {
|
|
249
|
+
dataArray.set(mutation, date, {
|
|
250
|
+
count: mutationEntry.count,
|
|
251
|
+
proportion: mutationEntry.proportion,
|
|
252
|
+
totalCount: mutationData.totalCount,
|
|
253
|
+
});
|
|
189
254
|
}
|
|
190
255
|
});
|
|
191
|
-
}
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
return dataArray;
|
|
192
259
|
}
|
|
193
260
|
|
|
194
261
|
function getTotalNumberOfSequencesInDateRange(filter: LapisFilter) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { queryAggregatedDataOverTime } from './queryAggregatedDataOverTime';
|
|
2
2
|
import { DivisionOperator } from '../operator/DivisionOperator';
|
|
3
3
|
import { type LapisFilter, type NamedLapisFilter, type TemporalGranularity } from '../types';
|
|
4
|
-
import { type
|
|
4
|
+
import { type TemporalClass } from '../utils/temporalClass';
|
|
5
5
|
import { makeArray } from '../utils/utils';
|
|
6
6
|
|
|
7
7
|
export type PrevalenceOverTimeData = PrevalenceOverTimeVariantData[];
|
|
@@ -15,7 +15,7 @@ export type PrevalenceOverTimeVariantDataPoint = {
|
|
|
15
15
|
count: number;
|
|
16
16
|
prevalence: number;
|
|
17
17
|
total: number;
|
|
18
|
-
dateRange:
|
|
18
|
+
dateRange: TemporalClass | null;
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
export function queryPrevalenceOverTime(
|