@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
|
@@ -1,190 +1,206 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { Deletion, Substitution } from '../../utils/mutations';
|
|
7
|
-
import { type
|
|
3
|
+
import { BaseMutationOverTimeDataMap } from './MutationOverTimeData';
|
|
4
|
+
import { getFilteredMutationOverTimeData } from './getFilteredMutationsOverTimeData';
|
|
5
|
+
import { type DeletionEntry, type SubstitutionEntry } from '../../types';
|
|
6
|
+
import { type Deletion, type Substitution } from '../../utils/mutations';
|
|
7
|
+
import { type TemporalClass } from '../../utils/temporalClass';
|
|
8
8
|
import { yearMonthDay } from '../../utils/temporalTestHelpers';
|
|
9
9
|
|
|
10
10
|
describe('getFilteredMutationOverTimeData', () => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
],
|
|
31
|
-
data,
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
expect(data.getFirstAxisKeys().length).to.equal(1);
|
|
35
|
-
expect(data.getFirstAxisKeys()[0].segment).to.equal('someOtherSegment');
|
|
36
|
-
});
|
|
11
|
+
it('should filter by displayed segments', () => {
|
|
12
|
+
const { data, overallMutationData } = prepareMutationOverTimeData([
|
|
13
|
+
someSubstitutionEntry,
|
|
14
|
+
anotherSubstitutionEntry,
|
|
15
|
+
someDeletionEntry,
|
|
16
|
+
]);
|
|
17
|
+
|
|
18
|
+
const result = getFilteredMutationOverTimeData(
|
|
19
|
+
data,
|
|
20
|
+
overallMutationData,
|
|
21
|
+
[
|
|
22
|
+
{ segment: 'someSegment', checked: false, label: 'Some Segment' },
|
|
23
|
+
{ segment: 'someOtherSegment', checked: true, label: 'Some Other Segment' },
|
|
24
|
+
],
|
|
25
|
+
[],
|
|
26
|
+
proportionInterval,
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
expect(result.getFirstAxisKeys()).to.deep.equal([anotherSubstitution]);
|
|
37
30
|
});
|
|
38
31
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
32
|
+
it('should filter by mutation types', () => {
|
|
33
|
+
const { data, overallMutationData } = prepareMutationOverTimeData([
|
|
34
|
+
someSubstitutionEntry,
|
|
35
|
+
anotherSubstitutionEntry,
|
|
36
|
+
someDeletionEntry,
|
|
37
|
+
]);
|
|
38
|
+
|
|
39
|
+
const result = getFilteredMutationOverTimeData(
|
|
40
|
+
data,
|
|
41
|
+
overallMutationData,
|
|
42
|
+
[],
|
|
43
|
+
[
|
|
44
|
+
{
|
|
45
|
+
type: 'substitution',
|
|
46
|
+
checked: false,
|
|
47
|
+
label: 'Substitution',
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
type: 'deletion',
|
|
51
|
+
checked: true,
|
|
52
|
+
label: 'Deletion',
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
proportionInterval,
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
expect(result.getFirstAxisKeys()).to.deep.equal([someDeletion]);
|
|
59
|
+
});
|
|
42
60
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
count: 2,
|
|
50
|
-
proportion: 0.2,
|
|
51
|
-
totalCount: 10,
|
|
52
|
-
});
|
|
61
|
+
it('should remove mutations where overall proportion is below filter', () => {
|
|
62
|
+
const { data, overallMutationData } = prepareMutationOverTimeData([
|
|
63
|
+
{ ...someSubstitutionEntry, proportion: belowFilter },
|
|
64
|
+
{ ...anotherSubstitutionEntry, proportion: inFilter },
|
|
65
|
+
{ ...someDeletionEntry, proportion: inFilter },
|
|
66
|
+
]);
|
|
53
67
|
|
|
54
|
-
|
|
55
|
-
[
|
|
56
|
-
{ type: 'substitution', checked: false, label: 'Substitution' },
|
|
57
|
-
{ type: 'deletion', checked: true, label: 'Deletion' },
|
|
58
|
-
],
|
|
59
|
-
data,
|
|
60
|
-
);
|
|
68
|
+
const result = getFilteredMutationOverTimeData(data, overallMutationData, [], [], proportionInterval);
|
|
61
69
|
|
|
62
|
-
|
|
63
|
-
expect(data.getFirstAxisKeys()[0].type).to.equal('deletion');
|
|
64
|
-
});
|
|
70
|
+
expect(result.getFirstAxisKeys()).to.deep.equal([anotherSubstitution, someDeletion]);
|
|
65
71
|
});
|
|
66
72
|
|
|
67
|
-
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const proportionInterval = { min: atFilterMin, max: atFilterMax };
|
|
74
|
-
|
|
75
|
-
const someSubstitution = new Substitution('someSegment', 'A', 'T', 123);
|
|
76
|
-
const someOtherMutation = new Substitution('someOtherSegment', 'A', 'G', 9);
|
|
77
|
-
|
|
78
|
-
it('should remove mutations where overall proportion is below filter', () => {
|
|
79
|
-
const data = getMutationOverTimeData();
|
|
80
|
-
|
|
81
|
-
filterProportion(data, getOverallMutationData(belowFilter), proportionInterval);
|
|
82
|
-
|
|
83
|
-
expect(
|
|
84
|
-
data.getAsArray({
|
|
85
|
-
count: 0,
|
|
86
|
-
proportion: 0,
|
|
87
|
-
totalCount: 10,
|
|
88
|
-
}),
|
|
89
|
-
).to.toHaveLength(0);
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
it('should remove mutations where overall proportion is above filter', () => {
|
|
93
|
-
const data = getMutationOverTimeData();
|
|
73
|
+
it('should remove mutations where overall proportion is above filter', () => {
|
|
74
|
+
const { data, overallMutationData } = prepareMutationOverTimeData([
|
|
75
|
+
{ ...someSubstitutionEntry, proportion: aboveFilter },
|
|
76
|
+
{ ...anotherSubstitutionEntry, proportion: inFilter },
|
|
77
|
+
{ ...someDeletionEntry, proportion: inFilter },
|
|
78
|
+
]);
|
|
94
79
|
|
|
95
|
-
|
|
80
|
+
const result = getFilteredMutationOverTimeData(data, overallMutationData, [], [], proportionInterval);
|
|
96
81
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
count: 0,
|
|
100
|
-
proportion: 0,
|
|
101
|
-
totalCount: 10,
|
|
102
|
-
}),
|
|
103
|
-
).to.toHaveLength(0);
|
|
104
|
-
});
|
|
82
|
+
expect(result.getFirstAxisKeys()).to.deep.equal([anotherSubstitution, someDeletion]);
|
|
83
|
+
});
|
|
105
84
|
|
|
106
|
-
|
|
107
|
-
|
|
85
|
+
it('should not remove mutations where overall proportion is above filter but single proportion is below filter', () => {
|
|
86
|
+
const { data, overallMutationData } = prepareMutationOverTimeData([
|
|
87
|
+
someSubstitutionEntry,
|
|
88
|
+
anotherSubstitutionEntry,
|
|
89
|
+
someDeletionEntry,
|
|
90
|
+
]);
|
|
91
|
+
data.set(someSubstitution, someTemporal, { ...someMutationOverTimeValue, proportion: belowFilter });
|
|
108
92
|
|
|
109
|
-
|
|
93
|
+
const result = getFilteredMutationOverTimeData(data, overallMutationData, [], [], proportionInterval);
|
|
110
94
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
count: 0,
|
|
114
|
-
proportion: 0,
|
|
115
|
-
totalCount: 10,
|
|
116
|
-
}),
|
|
117
|
-
).to.toHaveLength(0);
|
|
118
|
-
});
|
|
95
|
+
expect(result.getFirstAxisKeys()).to.deep.equal([someSubstitution, anotherSubstitution, someDeletion]);
|
|
96
|
+
});
|
|
119
97
|
|
|
120
|
-
|
|
121
|
-
|
|
98
|
+
it('should not remove mutations where overall proportion is below max but single proportion is above max', () => {
|
|
99
|
+
const { data, overallMutationData } = prepareMutationOverTimeData([
|
|
100
|
+
someSubstitutionEntry,
|
|
101
|
+
anotherSubstitutionEntry,
|
|
102
|
+
someDeletionEntry,
|
|
103
|
+
]);
|
|
104
|
+
data.set(someSubstitution, someTemporal, { ...someMutationOverTimeValue, proportion: aboveFilter });
|
|
122
105
|
|
|
123
|
-
|
|
106
|
+
const result = getFilteredMutationOverTimeData(data, overallMutationData, [], [], proportionInterval);
|
|
124
107
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
count: 0,
|
|
128
|
-
proportion: 0,
|
|
129
|
-
totalCount: 10,
|
|
130
|
-
}),
|
|
131
|
-
).to.toHaveLength(2);
|
|
132
|
-
});
|
|
108
|
+
expect(result.getFirstAxisKeys()).to.deep.equal([someSubstitution, anotherSubstitution, someDeletion]);
|
|
109
|
+
});
|
|
133
110
|
|
|
134
|
-
|
|
135
|
-
|
|
111
|
+
it('should not remove mutations where overall proportion is at lower bound of filter', () => {
|
|
112
|
+
const { data, overallMutationData } = prepareMutationOverTimeData([
|
|
113
|
+
{ ...someSubstitutionEntry, proportion: atFilterMin },
|
|
114
|
+
{ ...anotherSubstitutionEntry, proportion: inFilter },
|
|
115
|
+
{ ...someDeletionEntry, proportion: inFilter },
|
|
116
|
+
]);
|
|
117
|
+
const result = getFilteredMutationOverTimeData(data, overallMutationData, [], [], proportionInterval);
|
|
136
118
|
|
|
137
|
-
|
|
119
|
+
expect(result.getFirstAxisKeys()).to.deep.equal([someSubstitution, anotherSubstitution, someDeletion]);
|
|
120
|
+
});
|
|
138
121
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
).to.toHaveLength(2);
|
|
146
|
-
});
|
|
122
|
+
it('should not remove mutations where overall proportion is at upper bound of filter', () => {
|
|
123
|
+
const { data, overallMutationData } = prepareMutationOverTimeData([
|
|
124
|
+
{ ...someSubstitutionEntry, proportion: atFilterMax },
|
|
125
|
+
{ ...anotherSubstitutionEntry, proportion: inFilter },
|
|
126
|
+
{ ...someDeletionEntry, proportion: inFilter },
|
|
127
|
+
]);
|
|
147
128
|
|
|
148
|
-
|
|
149
|
-
const data = getMutationOverTimeData();
|
|
129
|
+
const result = getFilteredMutationOverTimeData(data, overallMutationData, [], [], proportionInterval);
|
|
150
130
|
|
|
151
|
-
|
|
131
|
+
expect(result.getFirstAxisKeys()).to.deep.equal([someSubstitution, anotherSubstitution, someDeletion]);
|
|
132
|
+
});
|
|
152
133
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
134
|
+
const belowFilter = 0.1;
|
|
135
|
+
const atFilterMin = 0.2;
|
|
136
|
+
const inFilter = 0.5;
|
|
137
|
+
const atFilterMax = 0.9;
|
|
138
|
+
const aboveFilter = 0.99;
|
|
139
|
+
const proportionInterval = { min: atFilterMin, max: atFilterMax };
|
|
140
|
+
|
|
141
|
+
const someSubstitution: Substitution = {
|
|
142
|
+
type: 'substitution',
|
|
143
|
+
valueAtReference: 'A',
|
|
144
|
+
substitutionValue: 'T',
|
|
145
|
+
code: 'A123T',
|
|
146
|
+
segment: 'someSegment',
|
|
147
|
+
position: 123,
|
|
148
|
+
};
|
|
149
|
+
const someSubstitutionEntry: SubstitutionEntry<Substitution> = {
|
|
150
|
+
type: 'substitution',
|
|
151
|
+
mutation: someSubstitution,
|
|
152
|
+
count: 234,
|
|
153
|
+
proportion: inFilter,
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
const anotherSubstitution: Substitution = {
|
|
157
|
+
type: 'substitution',
|
|
158
|
+
valueAtReference: 'G',
|
|
159
|
+
substitutionValue: 'C',
|
|
160
|
+
code: 'G345C',
|
|
161
|
+
segment: 'someOtherSegment',
|
|
162
|
+
position: 345,
|
|
163
|
+
};
|
|
164
|
+
const anotherSubstitutionEntry: SubstitutionEntry<Substitution> = {
|
|
165
|
+
type: 'substitution',
|
|
166
|
+
mutation: anotherSubstitution,
|
|
167
|
+
count: 456,
|
|
168
|
+
proportion: inFilter,
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const someDeletion: Deletion = {
|
|
172
|
+
type: 'deletion',
|
|
173
|
+
valueAtReference: 'A',
|
|
174
|
+
segment: 'someSegment',
|
|
175
|
+
position: 567,
|
|
176
|
+
code: 'A123-',
|
|
177
|
+
};
|
|
178
|
+
const someDeletionEntry: DeletionEntry<Deletion> = {
|
|
179
|
+
type: 'deletion',
|
|
180
|
+
mutation: someDeletion,
|
|
181
|
+
count: 789,
|
|
182
|
+
proportion: inFilter,
|
|
183
|
+
};
|
|
184
|
+
const someTemporal = yearMonthDay('2021-01-01');
|
|
185
|
+
const anotherTemporal = yearMonthDay('2021-02-02');
|
|
186
|
+
const someMutationOverTimeValue = {
|
|
187
|
+
count: 1,
|
|
188
|
+
proportion: inFilter,
|
|
189
|
+
totalCount: 10,
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
function prepareMutationOverTimeData(
|
|
193
|
+
mutationEntries: (SubstitutionEntry<Substitution> | DeletionEntry<Deletion>)[],
|
|
194
|
+
temporals: TemporalClass[] = [someTemporal, anotherTemporal],
|
|
195
|
+
) {
|
|
196
|
+
const data = new BaseMutationOverTimeDataMap();
|
|
197
|
+
|
|
198
|
+
temporals.forEach((temporal) => {
|
|
199
|
+
mutationEntries.forEach((entry) => {
|
|
200
|
+
data.set(entry.mutation, temporal, someMutationOverTimeValue);
|
|
201
|
+
});
|
|
160
202
|
});
|
|
161
203
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
data.set(someSubstitution, yearMonthDay('2021-01-01'), {
|
|
165
|
-
count: 1,
|
|
166
|
-
proportion: 0.1,
|
|
167
|
-
totalCount: 10,
|
|
168
|
-
});
|
|
169
|
-
data.set(someSubstitution, yearMonthDay('2021-02-02'), {
|
|
170
|
-
count: 99,
|
|
171
|
-
proportion: 0.99,
|
|
172
|
-
totalCount: 10,
|
|
173
|
-
});
|
|
174
|
-
return data;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
function getOverallMutationData(proportion: number = 0.1, mutation: Substitution = someSubstitution) {
|
|
178
|
-
return {
|
|
179
|
-
content: [
|
|
180
|
-
{
|
|
181
|
-
type: 'substitution' as const,
|
|
182
|
-
count: -1,
|
|
183
|
-
mutation,
|
|
184
|
-
proportion,
|
|
185
|
-
},
|
|
186
|
-
],
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
});
|
|
204
|
+
return { data, overallMutationData: mutationEntries };
|
|
205
|
+
}
|
|
190
206
|
});
|
|
@@ -1,76 +1,34 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import { type
|
|
3
|
-
import { type DeletionEntry, type SubstitutionEntry } from '../../types';
|
|
1
|
+
import { type MutationOverTimeDataMap } from './MutationOverTimeData';
|
|
2
|
+
import { type SubstitutionOrDeletionEntry } from '../../types';
|
|
4
3
|
import { Map2dView } from '../../utils/map2d';
|
|
4
|
+
import type { Deletion, Substitution } from '../../utils/mutations';
|
|
5
5
|
import type { DisplayedMutationType } from '../components/mutation-type-selector';
|
|
6
6
|
import type { DisplayedSegment } from '../components/segment-selector';
|
|
7
7
|
|
|
8
8
|
export function getFilteredMutationOverTimeData(
|
|
9
|
-
data:
|
|
10
|
-
overallMutationData:
|
|
9
|
+
data: MutationOverTimeDataMap,
|
|
10
|
+
overallMutationData: SubstitutionOrDeletionEntry<Substitution, Deletion>[],
|
|
11
11
|
displayedSegments: DisplayedSegment[],
|
|
12
12
|
displayedMutationTypes: DisplayedMutationType[],
|
|
13
13
|
proportionInterval: { min: number; max: number },
|
|
14
14
|
) {
|
|
15
15
|
const filteredData = new Map2dView(data);
|
|
16
|
-
filterDisplayedSegments(displayedSegments, filteredData);
|
|
17
|
-
filterMutationTypes(displayedMutationTypes, filteredData);
|
|
18
|
-
filterProportion(filteredData, overallMutationData, proportionInterval);
|
|
19
16
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
export function filterDisplayedSegments(
|
|
24
|
-
displayedSegments: DisplayedSegment[],
|
|
25
|
-
data: MutationOverTimeDataGroupedByMutation,
|
|
26
|
-
) {
|
|
27
|
-
displayedSegments.forEach((segment) => {
|
|
28
|
-
if (!segment.checked) {
|
|
29
|
-
data.getFirstAxisKeys().forEach((mutation) => {
|
|
30
|
-
if (mutation.segment === segment.segment) {
|
|
31
|
-
data.deleteRow(mutation);
|
|
32
|
-
}
|
|
33
|
-
});
|
|
17
|
+
const mutationsToFilterOut = overallMutationData.filter((entry) => {
|
|
18
|
+
if (entry.proportion < proportionInterval.min || entry.proportion > proportionInterval.max) {
|
|
19
|
+
return true;
|
|
34
20
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
export function filterMutationTypes(
|
|
39
|
-
displayedMutationTypes: DisplayedMutationType[],
|
|
40
|
-
data: MutationOverTimeDataGroupedByMutation,
|
|
41
|
-
) {
|
|
42
|
-
displayedMutationTypes.forEach((mutationType) => {
|
|
43
|
-
if (!mutationType.checked) {
|
|
44
|
-
data.getFirstAxisKeys().forEach((mutation) => {
|
|
45
|
-
if (mutationType.type === mutation.type) {
|
|
46
|
-
data.deleteRow(mutation);
|
|
47
|
-
}
|
|
48
|
-
});
|
|
21
|
+
if (displayedSegments.some((segment) => segment.segment === entry.mutation.segment && !segment.checked)) {
|
|
22
|
+
return true;
|
|
49
23
|
}
|
|
24
|
+
return displayedMutationTypes.some(
|
|
25
|
+
(mutationType) => mutationType.type === entry.mutation.type && !mutationType.checked,
|
|
26
|
+
);
|
|
50
27
|
});
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export function filterProportion(
|
|
54
|
-
data: MutationOverTimeDataGroupedByMutation,
|
|
55
|
-
overallMutationData: Dataset<SubstitutionEntry | DeletionEntry>,
|
|
56
|
-
proportionInterval: {
|
|
57
|
-
min: number;
|
|
58
|
-
max: number;
|
|
59
|
-
},
|
|
60
|
-
) {
|
|
61
|
-
const overallProportionsByMutation = overallMutationData.content.reduce(
|
|
62
|
-
(acc, { mutation, proportion }) => ({
|
|
63
|
-
...acc,
|
|
64
|
-
[mutation.toString()]: proportion,
|
|
65
|
-
}),
|
|
66
|
-
{} as Record<string, number>,
|
|
67
|
-
);
|
|
68
28
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
if (overallProportion < proportionInterval.min || overallProportion > proportionInterval.max) {
|
|
73
|
-
data.deleteRow(mutation);
|
|
74
|
-
}
|
|
29
|
+
mutationsToFilterOut.forEach((entry) => {
|
|
30
|
+
filteredData.deleteRow(entry.mutation);
|
|
75
31
|
});
|
|
32
|
+
|
|
33
|
+
return filteredData;
|
|
76
34
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { aminoAcidMutationsByDay } from './__mockData__/aminoAcidMutationsByDay';
|
|
2
|
+
import { getMutationOverTimeWorkerFunction, type MutationOverTimeWorkerResponse } from './mutationOverTimeWorker';
|
|
3
|
+
import { type MutationOverTimeQuery } from '../../query/queryMutationsOverTime';
|
|
4
|
+
import { workerFunction } from '../webWorkers/workerFunction';
|
|
5
|
+
import { byWeek } from './__mockData__/byWeek';
|
|
6
|
+
import { defaultMockData } from './__mockData__/defaultMockData';
|
|
7
|
+
import { getMutationOverTimeMock } from './__mockData__/mockConversion';
|
|
8
|
+
import { showsMessageWhenTooManyMutations } from './__mockData__/showsMessageWhenTooManyMutations';
|
|
9
|
+
|
|
10
|
+
const mockQueries: { query: MutationOverTimeQuery; response: MutationOverTimeWorkerResponse }[] = [
|
|
11
|
+
getMutationOverTimeMock(defaultMockData),
|
|
12
|
+
getMutationOverTimeMock(showsMessageWhenTooManyMutations),
|
|
13
|
+
getMutationOverTimeMock(byWeek),
|
|
14
|
+
getMutationOverTimeMock(aminoAcidMutationsByDay),
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
self.onmessage = async function (event: MessageEvent<MutationOverTimeQuery>) {
|
|
18
|
+
await workerFunction(async () => {
|
|
19
|
+
const query = mockQueries.find((mockQuery) => JSON.stringify(mockQuery.query) === JSON.stringify(event.data));
|
|
20
|
+
|
|
21
|
+
if (query !== undefined) {
|
|
22
|
+
return query.response;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return await getMutationOverTimeWorkerFunction(event);
|
|
26
|
+
});
|
|
27
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type MutationOverTimeMutationValue,
|
|
3
|
+
type MutationOverTimeQuery,
|
|
4
|
+
queryMutationsOverTimeData,
|
|
5
|
+
} from '../../query/queryMutationsOverTime';
|
|
6
|
+
import type { SubstitutionOrDeletionEntry } from '../../types';
|
|
7
|
+
import { type Map2DContents } from '../../utils/map2d';
|
|
8
|
+
import type { Deletion, Substitution } from '../../utils/mutations';
|
|
9
|
+
import type { Temporal } from '../../utils/temporalClass';
|
|
10
|
+
import { workerFunction } from '../webWorkers/workerFunction';
|
|
11
|
+
|
|
12
|
+
export type MutationOverTimeWorkerResponse = {
|
|
13
|
+
overallMutationData: SubstitutionOrDeletionEntry<Substitution, Deletion>[];
|
|
14
|
+
mutationOverTimeSerialized: Map2DContents<Substitution | Deletion, Temporal, MutationOverTimeMutationValue>;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export async function getMutationOverTimeWorkerFunction(event: MessageEvent<MutationOverTimeQuery>) {
|
|
18
|
+
const mutationOverTimeData = await queryMutationsOverTimeData(event.data);
|
|
19
|
+
|
|
20
|
+
const workerResponse: MutationOverTimeWorkerResponse = {
|
|
21
|
+
overallMutationData: mutationOverTimeData.overallMutationData,
|
|
22
|
+
mutationOverTimeSerialized: mutationOverTimeData.mutationOverTimeData.getContents(),
|
|
23
|
+
};
|
|
24
|
+
return workerResponse;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
self.onmessage = async function (event: MessageEvent<MutationOverTimeQuery>) {
|
|
28
|
+
await workerFunction(() => getMutationOverTimeWorkerFunction(event));
|
|
29
|
+
};
|
|
@@ -1,19 +1,16 @@
|
|
|
1
1
|
import { Fragment, type FunctionComponent, type RefObject } from 'preact';
|
|
2
2
|
import { useEffect, useRef, useState } from 'preact/hooks';
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
type MutationOverTimeMutationValue,
|
|
7
|
-
} from '../../query/queryMutationsOverTime';
|
|
4
|
+
import { type MutationOverTimeDataMap } from './MutationOverTimeData';
|
|
5
|
+
import { type MutationOverTimeMutationValue } from '../../query/queryMutationsOverTime';
|
|
8
6
|
import { type Deletion, type Substitution } from '../../utils/mutations';
|
|
9
|
-
import {
|
|
7
|
+
import { type Temporal, type TemporalClass, toTemporalClass, YearMonthDayClass } from '../../utils/temporalClass';
|
|
10
8
|
import { type ColorScale, getColorWithingScale, getTextColorForScale } from '../components/color-scale-selector';
|
|
11
9
|
import Tooltip, { type TooltipPosition } from '../components/tooltip';
|
|
12
|
-
import { sortSubstitutionsAndDeletions } from '../shared/sort/sortSubstitutionsAndDeletions';
|
|
13
10
|
import { formatProportion } from '../shared/table/formatProportion';
|
|
14
11
|
|
|
15
12
|
export interface MutationsOverTimeGridProps {
|
|
16
|
-
data:
|
|
13
|
+
data: MutationOverTimeDataMap;
|
|
17
14
|
colorScale: ColorScale;
|
|
18
15
|
}
|
|
19
16
|
|
|
@@ -21,10 +18,10 @@ const MAX_NUMBER_OF_GRID_ROWS = 100;
|
|
|
21
18
|
const MUTATION_CELL_WIDTH_REM = 8;
|
|
22
19
|
|
|
23
20
|
const MutationsOverTimeGrid: FunctionComponent<MutationsOverTimeGridProps> = ({ data, colorScale }) => {
|
|
24
|
-
const allMutations = data.getFirstAxisKeys()
|
|
21
|
+
const allMutations = data.getFirstAxisKeys();
|
|
25
22
|
const shownMutations = allMutations.slice(0, MAX_NUMBER_OF_GRID_ROWS);
|
|
26
23
|
|
|
27
|
-
const dates = data.getSecondAxisKeys()
|
|
24
|
+
const dates = data.getSecondAxisKeys();
|
|
28
25
|
|
|
29
26
|
const [showProportionText, setShowProportionText] = useState(false);
|
|
30
27
|
const gridRef = useRef<HTMLDivElement>(null);
|
|
@@ -128,12 +125,14 @@ const ProportionCell: FunctionComponent<{
|
|
|
128
125
|
showProportionText: boolean;
|
|
129
126
|
colorScale: ColorScale;
|
|
130
127
|
}> = ({ value, mutation, date, tooltipPosition, showProportionText, colorScale }) => {
|
|
128
|
+
const dateClass = toTemporalClass(date);
|
|
129
|
+
|
|
131
130
|
const tooltipContent = (
|
|
132
131
|
<div>
|
|
133
132
|
<p>
|
|
134
|
-
<span className='font-bold'>{
|
|
133
|
+
<span className='font-bold'>{dateClass.englishName()}</span>
|
|
135
134
|
</p>
|
|
136
|
-
<p>({timeIntervalDisplay(
|
|
135
|
+
<p>({timeIntervalDisplay(dateClass)})</p>
|
|
137
136
|
<p>{mutation.code}</p>
|
|
138
137
|
<p>Proportion: {formatProportion(value.proportion)}</p>
|
|
139
138
|
<p>
|
|
@@ -159,8 +158,8 @@ const ProportionCell: FunctionComponent<{
|
|
|
159
158
|
);
|
|
160
159
|
};
|
|
161
160
|
|
|
162
|
-
const timeIntervalDisplay = (date:
|
|
163
|
-
if (date instanceof
|
|
161
|
+
const timeIntervalDisplay = (date: TemporalClass) => {
|
|
162
|
+
if (date instanceof YearMonthDayClass) {
|
|
164
163
|
return date.toString();
|
|
165
164
|
}
|
|
166
165
|
|
|
@@ -168,7 +167,7 @@ const timeIntervalDisplay = (date: Temporal) => {
|
|
|
168
167
|
};
|
|
169
168
|
|
|
170
169
|
const MutationCell: FunctionComponent<{ mutation: Substitution | Deletion }> = ({ mutation }) => {
|
|
171
|
-
return <div className='text-center'>{mutation.
|
|
170
|
+
return <div className='text-center'>{mutation.code}</div>;
|
|
172
171
|
};
|
|
173
172
|
|
|
174
173
|
export default MutationsOverTimeGrid;
|