@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.
Files changed (118) hide show
  1. package/README.md +5 -12
  2. package/custom-elements.json +22 -22
  3. package/dist/assets/mutationOverTimeWorker-BOCXtKzd.js.map +1 -0
  4. package/dist/dashboard-components.js +301 -302
  5. package/dist/dashboard-components.js.map +1 -1
  6. package/dist/genspectrum-components.d.ts +60 -10
  7. package/dist/style.css +3 -2
  8. package/package.json +13 -4
  9. package/src/index.ts +1 -0
  10. package/src/operator/FetchInsertionsOperator.ts +2 -2
  11. package/src/operator/FetchSubstitutionsOrDeletionsOperator.ts +3 -3
  12. package/src/preact/dateRangeSelector/computeInitialValues.spec.ts +53 -38
  13. package/src/preact/dateRangeSelector/computeInitialValues.ts +17 -23
  14. package/src/preact/dateRangeSelector/date-range-selector.stories.tsx +46 -32
  15. package/src/preact/dateRangeSelector/date-range-selector.tsx +24 -26
  16. package/src/preact/dateRangeSelector/dateRangeOption.ts +65 -0
  17. package/src/preact/dateRangeSelector/selectableOptions.ts +17 -66
  18. package/src/preact/mutationComparison/fetchMutationData.spec.ts +3 -3
  19. package/src/preact/mutationComparison/getMutationComparisonTableData.spec.ts +11 -11
  20. package/src/preact/mutationComparison/getMutationComparisonTableData.ts +4 -4
  21. package/src/preact/mutationComparison/mutation-comparison-table.tsx +2 -2
  22. package/src/preact/mutationFilter/mutation-filter.tsx +27 -18
  23. package/src/preact/mutationFilter/parseAndValidateMutation.ts +4 -4
  24. package/src/preact/mutationFilter/parseMutation.spec.ts +17 -17
  25. package/src/preact/mutations/getInsertionsTableData.spec.ts +3 -3
  26. package/src/preact/mutations/getMutationsGridData.spec.ts +9 -9
  27. package/src/preact/mutations/getMutationsTableData.spec.ts +7 -7
  28. package/src/preact/mutations/mutations-insertions-table.tsx +3 -3
  29. package/src/preact/mutations/mutations-table.tsx +3 -3
  30. package/src/preact/mutationsOverTime/MutationOverTimeData.ts +20 -0
  31. package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutationsByDay.ts +45686 -0
  32. package/src/preact/mutationsOverTime/__mockData__/byWeek.ts +58989 -0
  33. package/src/preact/mutationsOverTime/__mockData__/defaultMockData.ts +103991 -0
  34. package/src/preact/mutationsOverTime/__mockData__/mockConversion.ts +54 -0
  35. package/src/preact/mutationsOverTime/__mockData__/showsMessageWhenTooManyMutations.ts +63690 -0
  36. package/src/preact/mutationsOverTime/getFilteredMutationsOverTime.spec.ts +177 -161
  37. package/src/preact/mutationsOverTime/getFilteredMutationsOverTimeData.ts +17 -59
  38. package/src/preact/mutationsOverTime/mutationOverTimeWorker.mock.ts +27 -0
  39. package/src/preact/mutationsOverTime/mutationOverTimeWorker.ts +29 -0
  40. package/src/preact/mutationsOverTime/mutations-over-time-grid.tsx +13 -14
  41. package/src/preact/mutationsOverTime/mutations-over-time.stories.tsx +9 -334
  42. package/src/preact/mutationsOverTime/mutations-over-time.tsx +59 -54
  43. package/src/preact/numberSequencesOverTime/getNumberOfSequencesOverTimeTableData.ts +3 -3
  44. package/src/preact/prevalenceOverTime/getPrevalenceOverTimeTableData.spec.ts +5 -5
  45. package/src/preact/prevalenceOverTime/prevalence-over-time-bubble-chart.tsx +1 -1
  46. package/src/preact/relativeGrowthAdvantage/relative-growth-advantage-chart.tsx +2 -2
  47. package/src/preact/shared/sort/sortInsertions.spec.ts +11 -11
  48. package/src/preact/shared/sort/sortInsertions.ts +2 -2
  49. package/src/preact/shared/sort/sortSubstitutionsAndDeletions.spec.ts +13 -13
  50. package/src/preact/shared/sort/sortSubstitutionsAndDeletions.ts +7 -4
  51. package/src/preact/webWorkers/useWebWorker.ts +51 -0
  52. package/src/preact/webWorkers/workerFunction.ts +14 -0
  53. package/src/query/queryAggregatedDataOverTime.ts +3 -3
  54. package/src/query/queryMutationsOverTime.spec.ts +272 -51
  55. package/src/query/queryMutationsOverTime.ts +114 -47
  56. package/src/query/queryPrevalenceOverTime.ts +2 -2
  57. package/src/query/queryRelativeGrowthAdvantage.ts +3 -3
  58. package/src/types.ts +25 -5
  59. package/src/utils/map2d.spec.ts +79 -12
  60. package/src/utils/map2d.ts +25 -5
  61. package/src/utils/mutations.spec.ts +20 -20
  62. package/src/utils/mutations.ts +80 -17
  63. package/src/utils/sort.ts +5 -2
  64. package/src/utils/temporal.spec.ts +27 -24
  65. package/src/utils/{temporal.ts → temporalClass.ts} +170 -72
  66. package/src/utils/temporalTestHelpers.ts +3 -3
  67. package/src/web-components/input/gs-date-range-selector.stories.ts +16 -28
  68. package/src/web-components/input/gs-date-range-selector.tsx +17 -32
  69. package/src/web-components/introduction.mdx +46 -0
  70. package/src/web-components/visualization/gs-mutations-over-time.stories.ts +6 -699
  71. package/src/web-components/visualization/gs-mutations-over-time.tsx +2 -2
  72. package/standalone-bundle/dashboard-components.js +12011 -12778
  73. package/standalone-bundle/dashboard-components.js.map +1 -1
  74. package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_01.json +0 -13
  75. package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_02.json +0 -13
  76. package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_03.json +0 -13
  77. package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_04.json +0 -13
  78. package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_05.json +0 -13
  79. package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_06.json +0 -13
  80. package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_07.json +0 -13
  81. package/src/preact/mutationsOverTime/__mockData__/aggregated_20_01_2024.json +0 -13
  82. package/src/preact/mutationsOverTime/__mockData__/aggregated_21_01_2024.json +0 -13
  83. package/src/preact/mutationsOverTime/__mockData__/aggregated_22_01_2024.json +0 -13
  84. package/src/preact/mutationsOverTime/__mockData__/aggregated_23_01_2024.json +0 -13
  85. package/src/preact/mutationsOverTime/__mockData__/aggregated_24_01_2024.json +0 -13
  86. package/src/preact/mutationsOverTime/__mockData__/aggregated_25_01_2024.json +0 -13
  87. package/src/preact/mutationsOverTime/__mockData__/aggregated_26_01_2024.json +0 -13
  88. package/src/preact/mutationsOverTime/__mockData__/aggregated_byDay.json +0 -38
  89. package/src/preact/mutationsOverTime/__mockData__/aggregated_byWeek.json +0 -122
  90. package/src/preact/mutationsOverTime/__mockData__/aggregated_date.json +0 -642
  91. package/src/preact/mutationsOverTime/__mockData__/aggregated_tooManyMutations.json +0 -1470
  92. package/src/preact/mutationsOverTime/__mockData__/aggregated_tooManyMutations_total.json +0 -13
  93. package/src/preact/mutationsOverTime/__mockData__/aggregated_week3_2024.json +0 -13
  94. package/src/preact/mutationsOverTime/__mockData__/aggregated_week4_2024.json +0 -13
  95. package/src/preact/mutationsOverTime/__mockData__/aggregated_week5_2024.json +0 -13
  96. package/src/preact/mutationsOverTime/__mockData__/aggregated_week6_2024.json +0 -13
  97. package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_20_01_2024.json +0 -6778
  98. package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_21_01_2024.json +0 -7129
  99. package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_22_01_2024.json +0 -4681
  100. package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_23_01_2024.json +0 -10738
  101. package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_24_01_2024.json +0 -11710
  102. package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_25_01_2024.json +0 -11557
  103. package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_26_01_2024.json +0 -8596
  104. package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_byDayOverall.json +0 -4726
  105. package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_01.json +0 -1747
  106. package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_02.json +0 -1774
  107. package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_03.json +0 -1819
  108. package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_04.json +0 -1864
  109. package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_05.json +0 -1927
  110. package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_06.json +0 -1864
  111. package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_07.json +0 -9
  112. package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_byMonthOverall.json +0 -11143
  113. package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_byWeekOverall.json +0 -9154
  114. package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_tooManyMutations.json +0 -16453
  115. package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_week3_2024.json +0 -8812
  116. package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_week4_2024.json +0 -9730
  117. package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_week5_2024.json +0 -9865
  118. 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 { filterDisplayedSegments, filterMutationTypes, filterProportion } from './getFilteredMutationsOverTimeData';
4
- import { type MutationOverTimeMutationValue } from '../../query/queryMutationsOverTime';
5
- import { Map2dBase } from '../../utils/map2d';
6
- import { Deletion, Substitution } from '../../utils/mutations';
7
- import { type Temporal } from '../../utils/temporal';
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
- describe('filterDisplayedSegments', () => {
12
- it('should filter by displayed segments', () => {
13
- const data = new Map2dBase<Substitution | Deletion, Temporal, MutationOverTimeMutationValue>();
14
-
15
- data.set(new Substitution('someSegment', 'A', 'T', 123), yearMonthDay('2021-01-01'), {
16
- count: 1,
17
- proportion: 0.1,
18
- totalCount: 10,
19
- });
20
- data.set(new Substitution('someOtherSegment', 'A', 'T', 123), yearMonthDay('2021-01-01'), {
21
- count: 2,
22
- proportion: 0.2,
23
- totalCount: 10,
24
- });
25
-
26
- filterDisplayedSegments(
27
- [
28
- { segment: 'someSegment', checked: false, label: 'Some Segment' },
29
- { segment: 'someOtherSegment', checked: true, label: 'Some Other Segment' },
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
- describe('filterMutationTypes', () => {
40
- it('should filter by mutation types', () => {
41
- const data = new Map2dBase<Substitution | Deletion, Temporal, MutationOverTimeMutationValue>();
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
- data.set(new Substitution('someSegment', 'A', 'T', 123), yearMonthDay('2021-01-01'), {
44
- count: 1,
45
- proportion: 0.1,
46
- totalCount: 10,
47
- });
48
- data.set(new Deletion('someOtherSegment', 'A', 123), yearMonthDay('2021-01-01'), {
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
- filterMutationTypes(
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
- expect(data.getFirstAxisKeys().length).to.equal(1);
63
- expect(data.getFirstAxisKeys()[0].type).to.equal('deletion');
64
- });
70
+ expect(result.getFirstAxisKeys()).to.deep.equal([anotherSubstitution, someDeletion]);
65
71
  });
66
72
 
67
- describe('filterProportion', () => {
68
- const belowFilter = 0.1;
69
- const atFilterMin = 0.2;
70
- const inFilter = 0.5;
71
- const atFilterMax = 0.9;
72
- const aboveFilter = 0.99;
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
- filterProportion(data, getOverallMutationData(aboveFilter), proportionInterval);
80
+ const result = getFilteredMutationOverTimeData(data, overallMutationData, [], [], proportionInterval);
96
81
 
97
- expect(
98
- data.getAsArray({
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
- it('should remove mutations where overall proportion is missing', () => {
107
- const data = getMutationOverTimeData();
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
- filterProportion(data, getOverallMutationData(aboveFilter, someOtherMutation), proportionInterval);
93
+ const result = getFilteredMutationOverTimeData(data, overallMutationData, [], [], proportionInterval);
110
94
 
111
- expect(
112
- data.getAsArray({
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
- it('should not remove mutation where overall proportion is at lower border of filter', () => {
121
- const data = getMutationOverTimeData();
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
- filterProportion(data, getOverallMutationData(inFilter), proportionInterval);
106
+ const result = getFilteredMutationOverTimeData(data, overallMutationData, [], [], proportionInterval);
124
107
 
125
- expect(
126
- data.getRow(someSubstitution, {
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
- it('should not remove mutation where overall proportion is within filter', () => {
135
- const data = getMutationOverTimeData();
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
- filterProportion(data, getOverallMutationData(inFilter), proportionInterval);
119
+ expect(result.getFirstAxisKeys()).to.deep.equal([someSubstitution, anotherSubstitution, someDeletion]);
120
+ });
138
121
 
139
- expect(
140
- data.getRow(someSubstitution, {
141
- count: 0,
142
- proportion: 0,
143
- totalCount: 10,
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
- it('should not remove mutation where overall proportion is at upper border of filter', () => {
149
- const data = getMutationOverTimeData();
129
+ const result = getFilteredMutationOverTimeData(data, overallMutationData, [], [], proportionInterval);
150
130
 
151
- filterProportion(data, getOverallMutationData(inFilter), proportionInterval);
131
+ expect(result.getFirstAxisKeys()).to.deep.equal([someSubstitution, anotherSubstitution, someDeletion]);
132
+ });
152
133
 
153
- expect(
154
- data.getRow(someSubstitution, {
155
- count: 0,
156
- proportion: 0,
157
- totalCount: 10,
158
- }),
159
- ).to.toHaveLength(2);
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
- function getMutationOverTimeData() {
163
- const data = new Map2dBase<Substitution | Deletion, Temporal, MutationOverTimeMutationValue>();
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 Dataset } from '../../operator/Dataset';
2
- import { type MutationOverTimeDataGroupedByMutation } from '../../query/queryMutationsOverTime';
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: MutationOverTimeDataGroupedByMutation,
10
- overallMutationData: Dataset<SubstitutionEntry | DeletionEntry>,
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
- return filteredData;
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
- data.getFirstAxisKeys().forEach((mutation) => {
70
- const overallProportion = overallProportionsByMutation[mutation.toString()] || -1;
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
- type MutationOverTimeDataGroupedByMutation,
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 { compareTemporal, type Temporal, YearMonthDay } from '../../utils/temporal';
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: MutationOverTimeDataGroupedByMutation;
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().sort(sortSubstitutionsAndDeletions);
21
+ const allMutations = data.getFirstAxisKeys();
25
22
  const shownMutations = allMutations.slice(0, MAX_NUMBER_OF_GRID_ROWS);
26
23
 
27
- const dates = data.getSecondAxisKeys().sort((a, b) => compareTemporal(a, b));
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'>{date.englishName()}</span>
133
+ <span className='font-bold'>{dateClass.englishName()}</span>
135
134
  </p>
136
- <p>({timeIntervalDisplay(date)})</p>
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: Temporal) => {
163
- if (date instanceof YearMonthDay) {
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.toString()}</div>;
170
+ return <div className='text-center'>{mutation.code}</div>;
172
171
  };
173
172
 
174
173
  export default MutationsOverTimeGrid;