@genspectrum/dashboard-components 0.6.18 → 0.6.19
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 +4 -4
- package/dist/assets/mutationOverTimeWorker-BdzqDqvO.js.map +1 -0
- package/dist/dashboard-components.js +216 -214
- package/dist/dashboard-components.js.map +1 -1
- package/dist/genspectrum-components.d.ts +40 -40
- package/dist/style.css +3 -2
- package/package.json +13 -2
- package/src/operator/FetchInsertionsOperator.ts +2 -2
- package/src/operator/FetchSubstitutionsOrDeletionsOperator.ts +3 -3
- 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/__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 +176 -159
- 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 +68 -52
- 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 -45
- 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 +29 -1
- package/src/utils/map2d.ts +22 -1
- 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/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 +13763 -13754
- 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,207 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { getFilteredMutationOverTimeData } from './getFilteredMutationsOverTimeData';
|
|
4
4
|
import { type MutationOverTimeMutationValue } from '../../query/queryMutationsOverTime';
|
|
5
|
+
import { type DeletionEntry, type SubstitutionEntry } from '../../types';
|
|
5
6
|
import { Map2dBase } from '../../utils/map2d';
|
|
6
|
-
import { Deletion, Substitution } from '../../utils/mutations';
|
|
7
|
-
import { type
|
|
7
|
+
import { type Deletion, type Substitution } from '../../utils/mutations';
|
|
8
|
+
import { type TemporalClass } from '../../utils/temporalClass';
|
|
8
9
|
import { yearMonthDay } from '../../utils/temporalTestHelpers';
|
|
9
10
|
|
|
10
11
|
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
|
-
});
|
|
12
|
+
it('should filter by displayed segments', () => {
|
|
13
|
+
const { data, overallMutationData } = prepareMutationOverTimeData([
|
|
14
|
+
someSubstitutionEntry,
|
|
15
|
+
anotherSubstitutionEntry,
|
|
16
|
+
someDeletionEntry,
|
|
17
|
+
]);
|
|
18
|
+
|
|
19
|
+
const result = getFilteredMutationOverTimeData(
|
|
20
|
+
data,
|
|
21
|
+
overallMutationData,
|
|
22
|
+
[
|
|
23
|
+
{ segment: 'someSegment', checked: false, label: 'Some Segment' },
|
|
24
|
+
{ segment: 'someOtherSegment', checked: true, label: 'Some Other Segment' },
|
|
25
|
+
],
|
|
26
|
+
[],
|
|
27
|
+
proportionInterval,
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
expect(result.getFirstAxisKeys()).to.deep.equal([anotherSubstitution]);
|
|
37
31
|
});
|
|
38
32
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
33
|
+
it('should filter by mutation types', () => {
|
|
34
|
+
const { data, overallMutationData } = prepareMutationOverTimeData([
|
|
35
|
+
someSubstitutionEntry,
|
|
36
|
+
anotherSubstitutionEntry,
|
|
37
|
+
someDeletionEntry,
|
|
38
|
+
]);
|
|
39
|
+
|
|
40
|
+
const result = getFilteredMutationOverTimeData(
|
|
41
|
+
data,
|
|
42
|
+
overallMutationData,
|
|
43
|
+
[],
|
|
44
|
+
[
|
|
45
|
+
{
|
|
46
|
+
type: 'substitution',
|
|
47
|
+
checked: false,
|
|
48
|
+
label: 'Substitution',
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
type: 'deletion',
|
|
52
|
+
checked: true,
|
|
53
|
+
label: 'Deletion',
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
proportionInterval,
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
expect(result.getFirstAxisKeys()).to.deep.equal([someDeletion]);
|
|
60
|
+
});
|
|
42
61
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
count: 2,
|
|
50
|
-
proportion: 0.2,
|
|
51
|
-
totalCount: 10,
|
|
52
|
-
});
|
|
62
|
+
it('should remove mutations where overall proportion is below filter', () => {
|
|
63
|
+
const { data, overallMutationData } = prepareMutationOverTimeData([
|
|
64
|
+
{ ...someSubstitutionEntry, proportion: belowFilter },
|
|
65
|
+
{ ...anotherSubstitutionEntry, proportion: inFilter },
|
|
66
|
+
{ ...someDeletionEntry, proportion: inFilter },
|
|
67
|
+
]);
|
|
53
68
|
|
|
54
|
-
|
|
55
|
-
[
|
|
56
|
-
{ type: 'substitution', checked: false, label: 'Substitution' },
|
|
57
|
-
{ type: 'deletion', checked: true, label: 'Deletion' },
|
|
58
|
-
],
|
|
59
|
-
data,
|
|
60
|
-
);
|
|
69
|
+
const result = getFilteredMutationOverTimeData(data, overallMutationData, [], [], proportionInterval);
|
|
61
70
|
|
|
62
|
-
|
|
63
|
-
expect(data.getFirstAxisKeys()[0].type).to.equal('deletion');
|
|
64
|
-
});
|
|
71
|
+
expect(result.getFirstAxisKeys()).to.deep.equal([anotherSubstitution, someDeletion]);
|
|
65
72
|
});
|
|
66
73
|
|
|
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();
|
|
74
|
+
it('should remove mutations where overall proportion is above filter', () => {
|
|
75
|
+
const { data, overallMutationData } = prepareMutationOverTimeData([
|
|
76
|
+
{ ...someSubstitutionEntry, proportion: aboveFilter },
|
|
77
|
+
{ ...anotherSubstitutionEntry, proportion: inFilter },
|
|
78
|
+
{ ...someDeletionEntry, proportion: inFilter },
|
|
79
|
+
]);
|
|
94
80
|
|
|
95
|
-
|
|
81
|
+
const result = getFilteredMutationOverTimeData(data, overallMutationData, [], [], proportionInterval);
|
|
96
82
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
count: 0,
|
|
100
|
-
proportion: 0,
|
|
101
|
-
totalCount: 10,
|
|
102
|
-
}),
|
|
103
|
-
).to.toHaveLength(0);
|
|
104
|
-
});
|
|
83
|
+
expect(result.getFirstAxisKeys()).to.deep.equal([anotherSubstitution, someDeletion]);
|
|
84
|
+
});
|
|
105
85
|
|
|
106
|
-
|
|
107
|
-
|
|
86
|
+
it('should not remove mutations where overall proportion is above filter but single proportion is below filter', () => {
|
|
87
|
+
const { data, overallMutationData } = prepareMutationOverTimeData([
|
|
88
|
+
someSubstitutionEntry,
|
|
89
|
+
anotherSubstitutionEntry,
|
|
90
|
+
someDeletionEntry,
|
|
91
|
+
]);
|
|
92
|
+
data.set(someSubstitution, someTemporal, { ...someMutationOverTimeValue, proportion: belowFilter });
|
|
108
93
|
|
|
109
|
-
|
|
94
|
+
const result = getFilteredMutationOverTimeData(data, overallMutationData, [], [], proportionInterval);
|
|
110
95
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
count: 0,
|
|
114
|
-
proportion: 0,
|
|
115
|
-
totalCount: 10,
|
|
116
|
-
}),
|
|
117
|
-
).to.toHaveLength(0);
|
|
118
|
-
});
|
|
96
|
+
expect(result.getFirstAxisKeys()).to.deep.equal([someSubstitution, anotherSubstitution, someDeletion]);
|
|
97
|
+
});
|
|
119
98
|
|
|
120
|
-
|
|
121
|
-
|
|
99
|
+
it('should not remove mutations where overall proportion is below max but single proportion is above max', () => {
|
|
100
|
+
const { data, overallMutationData } = prepareMutationOverTimeData([
|
|
101
|
+
someSubstitutionEntry,
|
|
102
|
+
anotherSubstitutionEntry,
|
|
103
|
+
someDeletionEntry,
|
|
104
|
+
]);
|
|
105
|
+
data.set(someSubstitution, someTemporal, { ...someMutationOverTimeValue, proportion: aboveFilter });
|
|
122
106
|
|
|
123
|
-
|
|
107
|
+
const result = getFilteredMutationOverTimeData(data, overallMutationData, [], [], proportionInterval);
|
|
124
108
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
count: 0,
|
|
128
|
-
proportion: 0,
|
|
129
|
-
totalCount: 10,
|
|
130
|
-
}),
|
|
131
|
-
).to.toHaveLength(2);
|
|
132
|
-
});
|
|
109
|
+
expect(result.getFirstAxisKeys()).to.deep.equal([someSubstitution, anotherSubstitution, someDeletion]);
|
|
110
|
+
});
|
|
133
111
|
|
|
134
|
-
|
|
135
|
-
|
|
112
|
+
it('should not remove mutations where overall proportion is at lower bound of filter', () => {
|
|
113
|
+
const { data, overallMutationData } = prepareMutationOverTimeData([
|
|
114
|
+
{ ...someSubstitutionEntry, proportion: atFilterMin },
|
|
115
|
+
{ ...anotherSubstitutionEntry, proportion: inFilter },
|
|
116
|
+
{ ...someDeletionEntry, proportion: inFilter },
|
|
117
|
+
]);
|
|
118
|
+
const result = getFilteredMutationOverTimeData(data, overallMutationData, [], [], proportionInterval);
|
|
136
119
|
|
|
137
|
-
|
|
120
|
+
expect(result.getFirstAxisKeys()).to.deep.equal([someSubstitution, anotherSubstitution, someDeletion]);
|
|
121
|
+
});
|
|
138
122
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
).to.toHaveLength(2);
|
|
146
|
-
});
|
|
123
|
+
it('should not remove mutations where overall proportion is at upper bound of filter', () => {
|
|
124
|
+
const { data, overallMutationData } = prepareMutationOverTimeData([
|
|
125
|
+
{ ...someSubstitutionEntry, proportion: atFilterMax },
|
|
126
|
+
{ ...anotherSubstitutionEntry, proportion: inFilter },
|
|
127
|
+
{ ...someDeletionEntry, proportion: inFilter },
|
|
128
|
+
]);
|
|
147
129
|
|
|
148
|
-
|
|
149
|
-
const data = getMutationOverTimeData();
|
|
130
|
+
const result = getFilteredMutationOverTimeData(data, overallMutationData, [], [], proportionInterval);
|
|
150
131
|
|
|
151
|
-
|
|
132
|
+
expect(result.getFirstAxisKeys()).to.deep.equal([someSubstitution, anotherSubstitution, someDeletion]);
|
|
133
|
+
});
|
|
152
134
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
135
|
+
const belowFilter = 0.1;
|
|
136
|
+
const atFilterMin = 0.2;
|
|
137
|
+
const inFilter = 0.5;
|
|
138
|
+
const atFilterMax = 0.9;
|
|
139
|
+
const aboveFilter = 0.99;
|
|
140
|
+
const proportionInterval = { min: atFilterMin, max: atFilterMax };
|
|
141
|
+
|
|
142
|
+
const someSubstitution: Substitution = {
|
|
143
|
+
type: 'substitution',
|
|
144
|
+
valueAtReference: 'A',
|
|
145
|
+
substitutionValue: 'T',
|
|
146
|
+
code: 'A123T',
|
|
147
|
+
segment: 'someSegment',
|
|
148
|
+
position: 123,
|
|
149
|
+
};
|
|
150
|
+
const someSubstitutionEntry: SubstitutionEntry<Substitution> = {
|
|
151
|
+
type: 'substitution',
|
|
152
|
+
mutation: someSubstitution,
|
|
153
|
+
count: 234,
|
|
154
|
+
proportion: inFilter,
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const anotherSubstitution: Substitution = {
|
|
158
|
+
type: 'substitution',
|
|
159
|
+
valueAtReference: 'G',
|
|
160
|
+
substitutionValue: 'C',
|
|
161
|
+
code: 'G345C',
|
|
162
|
+
segment: 'someOtherSegment',
|
|
163
|
+
position: 345,
|
|
164
|
+
};
|
|
165
|
+
const anotherSubstitutionEntry: SubstitutionEntry<Substitution> = {
|
|
166
|
+
type: 'substitution',
|
|
167
|
+
mutation: anotherSubstitution,
|
|
168
|
+
count: 456,
|
|
169
|
+
proportion: inFilter,
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const someDeletion: Deletion = {
|
|
173
|
+
type: 'deletion',
|
|
174
|
+
valueAtReference: 'A',
|
|
175
|
+
segment: 'someSegment',
|
|
176
|
+
position: 567,
|
|
177
|
+
code: 'A123-',
|
|
178
|
+
};
|
|
179
|
+
const someDeletionEntry: DeletionEntry<Deletion> = {
|
|
180
|
+
type: 'deletion',
|
|
181
|
+
mutation: someDeletion,
|
|
182
|
+
count: 789,
|
|
183
|
+
proportion: inFilter,
|
|
184
|
+
};
|
|
185
|
+
const someTemporal = yearMonthDay('2021-01-01');
|
|
186
|
+
const anotherTemporal = yearMonthDay('2021-02-02');
|
|
187
|
+
const someMutationOverTimeValue = {
|
|
188
|
+
count: 1,
|
|
189
|
+
proportion: inFilter,
|
|
190
|
+
totalCount: 10,
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
function prepareMutationOverTimeData(
|
|
194
|
+
mutationEntries: (SubstitutionEntry<Substitution> | DeletionEntry<Deletion>)[],
|
|
195
|
+
temporals: TemporalClass[] = [someTemporal, anotherTemporal],
|
|
196
|
+
) {
|
|
197
|
+
const data = new Map2dBase<Substitution | Deletion, TemporalClass, MutationOverTimeMutationValue>();
|
|
198
|
+
|
|
199
|
+
temporals.forEach((temporal) => {
|
|
200
|
+
mutationEntries.forEach((entry) => {
|
|
201
|
+
data.set(entry.mutation, temporal, someMutationOverTimeValue);
|
|
202
|
+
});
|
|
160
203
|
});
|
|
161
204
|
|
|
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
|
-
});
|
|
205
|
+
return { data, overallMutationData: mutationEntries };
|
|
206
|
+
}
|
|
190
207
|
});
|
|
@@ -1,76 +1,34 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import { type
|
|
3
|
-
import { type DeletionEntry, type SubstitutionEntry } from '../../types';
|
|
1
|
+
import { type MutationOverTimeData } from './mutations-over-time';
|
|
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: MutationOverTimeData,
|
|
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 MutationOverTimeData } from './mutations-over-time';
|
|
5
|
+
import { type MutationOverTimeMutationValue } from '../../query/queryMutationsOverTime';
|
|
8
6
|
import { type Deletion, type Substitution } from '../../utils/mutations';
|
|
9
|
-
import {
|
|
7
|
+
import { toTemporalClass, type Temporal, type TemporalClass, 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: MutationOverTimeData;
|
|
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;
|