@genspectrum/dashboard-components 1.8.0 → 1.8.2
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 +22 -2
- package/dist/assets/{mutationOverTimeWorker-DPS3tmOd.js.map → mutationOverTimeWorker-dhufsWQ2.js.map} +1 -1
- package/dist/components.d.ts +10 -10
- package/dist/components.js +21 -14
- package/dist/components.js.map +1 -1
- package/dist/util.d.ts +10 -10
- package/package.json +1 -1
- package/src/preact/mutationsOverTime/__mockData__/withGaps.ts +0 -54
- package/src/preact/mutationsOverTime/mutations-over-time-grid.tsx +6 -2
- package/src/preact/wastewater/mutationsOverTime/__mockData__/detailsAminAcidNonSegmented.json +88 -0
- package/src/preact/wastewater/mutationsOverTime/wastewater-mutations-over-time.stories.tsx +34 -0
- package/src/query/queryMutationsOverTime.ts +28 -11
- package/src/query/queryMutationsOverTimeNewEndpoint.spec.ts +6 -6
- package/src/query/queryWastewaterMutationsOverTime.ts +1 -1
- package/src/utils/mutations.ts +18 -10
- package/standalone-bundle/assets/{mutationOverTimeWorker-Dp-A14AP.js.map → mutationOverTimeWorker-CGqPKySO.js.map} +1 -1
- package/standalone-bundle/dashboard-components.js +2696 -2695
- package/standalone-bundle/dashboard-components.js.map +1 -1
package/dist/util.d.ts
CHANGED
|
@@ -1037,7 +1037,7 @@ declare global {
|
|
|
1037
1037
|
|
|
1038
1038
|
declare global {
|
|
1039
1039
|
interface HTMLElementTagNameMap {
|
|
1040
|
-
'gs-
|
|
1040
|
+
'gs-mutations-over-time': MutationsOverTimeComponent;
|
|
1041
1041
|
}
|
|
1042
1042
|
}
|
|
1043
1043
|
|
|
@@ -1045,7 +1045,7 @@ declare global {
|
|
|
1045
1045
|
declare global {
|
|
1046
1046
|
namespace JSX {
|
|
1047
1047
|
interface IntrinsicElements {
|
|
1048
|
-
'gs-
|
|
1048
|
+
'gs-mutations-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1049
1049
|
}
|
|
1050
1050
|
}
|
|
1051
1051
|
}
|
|
@@ -1053,7 +1053,7 @@ declare global {
|
|
|
1053
1053
|
|
|
1054
1054
|
declare global {
|
|
1055
1055
|
interface HTMLElementTagNameMap {
|
|
1056
|
-
'gs-
|
|
1056
|
+
'gs-number-sequences-over-time': NumberSequencesOverTimeComponent;
|
|
1057
1057
|
}
|
|
1058
1058
|
}
|
|
1059
1059
|
|
|
@@ -1061,7 +1061,7 @@ declare global {
|
|
|
1061
1061
|
declare global {
|
|
1062
1062
|
namespace JSX {
|
|
1063
1063
|
interface IntrinsicElements {
|
|
1064
|
-
'gs-
|
|
1064
|
+
'gs-number-sequences-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1065
1065
|
}
|
|
1066
1066
|
}
|
|
1067
1067
|
}
|
|
@@ -1137,10 +1137,10 @@ declare global {
|
|
|
1137
1137
|
|
|
1138
1138
|
declare global {
|
|
1139
1139
|
interface HTMLElementTagNameMap {
|
|
1140
|
-
'gs-
|
|
1140
|
+
'gs-location-filter': LocationFilterComponent;
|
|
1141
1141
|
}
|
|
1142
1142
|
interface HTMLElementEventMap {
|
|
1143
|
-
[gsEventNames.
|
|
1143
|
+
[gsEventNames.locationChanged]: LocationChangedEvent;
|
|
1144
1144
|
}
|
|
1145
1145
|
}
|
|
1146
1146
|
|
|
@@ -1148,7 +1148,7 @@ declare global {
|
|
|
1148
1148
|
declare global {
|
|
1149
1149
|
namespace JSX {
|
|
1150
1150
|
interface IntrinsicElements {
|
|
1151
|
-
'gs-
|
|
1151
|
+
'gs-location-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1152
1152
|
}
|
|
1153
1153
|
}
|
|
1154
1154
|
}
|
|
@@ -1156,10 +1156,10 @@ declare global {
|
|
|
1156
1156
|
|
|
1157
1157
|
declare global {
|
|
1158
1158
|
interface HTMLElementTagNameMap {
|
|
1159
|
-
'gs-
|
|
1159
|
+
'gs-text-filter': TextFilterComponent;
|
|
1160
1160
|
}
|
|
1161
1161
|
interface HTMLElementEventMap {
|
|
1162
|
-
[gsEventNames.
|
|
1162
|
+
[gsEventNames.textFilterChanged]: TextFilterChangedEvent;
|
|
1163
1163
|
}
|
|
1164
1164
|
}
|
|
1165
1165
|
|
|
@@ -1167,7 +1167,7 @@ declare global {
|
|
|
1167
1167
|
declare global {
|
|
1168
1168
|
namespace JSX {
|
|
1169
1169
|
interface IntrinsicElements {
|
|
1170
|
-
'gs-
|
|
1170
|
+
'gs-text-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1171
1171
|
}
|
|
1172
1172
|
}
|
|
1173
1173
|
}
|
package/package.json
CHANGED
|
@@ -80,15 +80,6 @@ export const withGaps: MutationOverTimeMockData = {
|
|
|
80
80
|
totalCount: 8236,
|
|
81
81
|
},
|
|
82
82
|
],
|
|
83
|
-
[
|
|
84
|
-
'2024-04',
|
|
85
|
-
{
|
|
86
|
-
type: 'value',
|
|
87
|
-
count: 0,
|
|
88
|
-
proportion: NaN,
|
|
89
|
-
totalCount: 0,
|
|
90
|
-
},
|
|
91
|
-
],
|
|
92
83
|
[
|
|
93
84
|
'2024-05',
|
|
94
85
|
{
|
|
@@ -98,15 +89,6 @@ export const withGaps: MutationOverTimeMockData = {
|
|
|
98
89
|
totalCount: 8799,
|
|
99
90
|
},
|
|
100
91
|
],
|
|
101
|
-
[
|
|
102
|
-
'2024-06',
|
|
103
|
-
{
|
|
104
|
-
type: 'value',
|
|
105
|
-
count: 0,
|
|
106
|
-
proportion: NaN,
|
|
107
|
-
totalCount: 0,
|
|
108
|
-
},
|
|
109
|
-
],
|
|
110
92
|
[
|
|
111
93
|
'2024-07',
|
|
112
94
|
{
|
|
@@ -148,15 +130,6 @@ export const withGaps: MutationOverTimeMockData = {
|
|
|
148
130
|
totalCount: 8236,
|
|
149
131
|
},
|
|
150
132
|
],
|
|
151
|
-
[
|
|
152
|
-
'2024-04',
|
|
153
|
-
{
|
|
154
|
-
type: 'value',
|
|
155
|
-
count: 0,
|
|
156
|
-
proportion: NaN,
|
|
157
|
-
totalCount: 0,
|
|
158
|
-
},
|
|
159
|
-
],
|
|
160
133
|
[
|
|
161
134
|
'2024-05',
|
|
162
135
|
{
|
|
@@ -166,15 +139,6 @@ export const withGaps: MutationOverTimeMockData = {
|
|
|
166
139
|
totalCount: 8799,
|
|
167
140
|
},
|
|
168
141
|
],
|
|
169
|
-
[
|
|
170
|
-
'2024-06',
|
|
171
|
-
{
|
|
172
|
-
type: 'value',
|
|
173
|
-
count: 0,
|
|
174
|
-
proportion: NaN,
|
|
175
|
-
totalCount: 0,
|
|
176
|
-
},
|
|
177
|
-
],
|
|
178
142
|
[
|
|
179
143
|
'2024-07',
|
|
180
144
|
{
|
|
@@ -212,15 +176,6 @@ export const withGaps: MutationOverTimeMockData = {
|
|
|
212
176
|
totalCount: 8236,
|
|
213
177
|
},
|
|
214
178
|
],
|
|
215
|
-
[
|
|
216
|
-
'2024-04',
|
|
217
|
-
{
|
|
218
|
-
type: 'value',
|
|
219
|
-
count: 0,
|
|
220
|
-
proportion: NaN,
|
|
221
|
-
totalCount: 0,
|
|
222
|
-
},
|
|
223
|
-
],
|
|
224
179
|
[
|
|
225
180
|
'2024-05',
|
|
226
181
|
{
|
|
@@ -230,15 +185,6 @@ export const withGaps: MutationOverTimeMockData = {
|
|
|
230
185
|
totalCount: 8799,
|
|
231
186
|
},
|
|
232
187
|
],
|
|
233
|
-
[
|
|
234
|
-
'2024-06',
|
|
235
|
-
{
|
|
236
|
-
type: 'value',
|
|
237
|
-
count: 0,
|
|
238
|
-
proportion: NaN,
|
|
239
|
-
totalCount: 0,
|
|
240
|
-
},
|
|
241
|
-
],
|
|
242
188
|
[
|
|
243
189
|
'2024-07',
|
|
244
190
|
{
|
|
@@ -21,6 +21,8 @@ import {
|
|
|
21
21
|
usePreactTable,
|
|
22
22
|
} from '../shared/tanstackTable/tanstackTable';
|
|
23
23
|
|
|
24
|
+
const NON_BREAKING_SPACE = '\u00A0';
|
|
25
|
+
|
|
24
26
|
export interface MutationsOverTimeGridProps {
|
|
25
27
|
data: MutationOverTimeDataMap;
|
|
26
28
|
colorScale: ColorScale;
|
|
@@ -176,7 +178,7 @@ const ProportionCell: FunctionComponent<{
|
|
|
176
178
|
tooltipPosition: TooltipPosition;
|
|
177
179
|
colorScale: ColorScale;
|
|
178
180
|
}> = ({ value, mutation, date, tooltipPosition, colorScale }) => {
|
|
179
|
-
const proportion = value?.type === 'belowThreshold' ?
|
|
181
|
+
const proportion = value?.type === 'belowThreshold' ? undefined : value?.proportion;
|
|
180
182
|
|
|
181
183
|
return (
|
|
182
184
|
<div className={'py-1 w-full h-full'}>
|
|
@@ -194,7 +196,9 @@ const ProportionCell: FunctionComponent<{
|
|
|
194
196
|
{value === null ? (
|
|
195
197
|
<span className='invisible'>No data</span>
|
|
196
198
|
) : (
|
|
197
|
-
<span className='invisible @[2rem]:visible'>
|
|
199
|
+
<span className='invisible @[2rem]:visible'>
|
|
200
|
+
{proportion !== undefined ? formatProportion(proportion, 0) : NON_BREAKING_SPACE}
|
|
201
|
+
</span>
|
|
198
202
|
)}
|
|
199
203
|
</div>
|
|
200
204
|
</Tooltip>
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
{
|
|
2
|
+
"data": [
|
|
3
|
+
{
|
|
4
|
+
"aminoAcidMutationFrequency": null,
|
|
5
|
+
"date": "2024-11-13",
|
|
6
|
+
"location": "Lugano",
|
|
7
|
+
"nucleotideMutationFrequency": "{\"A12183T\": null, \"C2554T\": null, \"C3422A\": 0.9598659873008728, \"A966C\": null, \"G6661A\": 0.5527499914169312, \"G7731A\": 0.9832900166511536, \"T4026G\": 0.9991809725761414, \"T5260C\": null, \"T5287C\": null}",
|
|
8
|
+
"reference": "RSV-B"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"aminoAcidMutationFrequency": null,
|
|
12
|
+
"date": "2024-11-17",
|
|
13
|
+
"location": "Genève",
|
|
14
|
+
"nucleotideMutationFrequency": "{\"A12183T\": 1.0, \"C2554T\": null, \"C3422A\": 0.0, \"A966C\": null, \"G6661A\": 0.8785049915313721, \"G7731A\": 0.9855599999427795, \"T4026G\": null, \"T5260C\": 1.0, \"T5287C\": 0.9932659864425659}",
|
|
15
|
+
"reference": "RSV-B"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"aminoAcidMutationFrequency": "{\"S4286C\": null, \"R346T\": 0.25, \"Q493E\": 0.60, \"G204P\": null}",
|
|
19
|
+
"date": "2024-11-17",
|
|
20
|
+
"location": "Lugano",
|
|
21
|
+
"nucleotideMutationFrequency": "{\"A12183T\": 0.998993992805481, \"C2554T\": null, \"C3422A\": null, \"A966C\": null, \"G6661A\": 0.8917459845542908, \"G7731A\": 0.9770470261573792, \"T4026G\": 0.0, \"T5260C\": null, \"T5287C\": null}",
|
|
22
|
+
"reference": "RSV-B"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"aminoAcidMutationFrequency": "{\"S4286C\": 0.42, \"R346T\": 0.22, \"Q493E\": 0.66, \"G204P\": null}",
|
|
26
|
+
"date": "2024-11-16",
|
|
27
|
+
"location": "Lugano",
|
|
28
|
+
"nucleotideMutationFrequency": "{\"A12183T\": null, \"C2554T\": null, \"C3422A\": null, \"A966C\": null, \"G6661A\": 0.9476320147514343, \"G7731A\": 0.9809200167655945, \"T4026G\": 0.9992259740829468, \"T5260C\": null, \"T5287C\": null}",
|
|
29
|
+
"reference": "RSV-B"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"aminoAcidMutationFrequency": null,
|
|
33
|
+
"date": "2024-11-18",
|
|
34
|
+
"location": "Genève",
|
|
35
|
+
"nucleotideMutationFrequency": "{\"A12183T\": null, \"C2554T\": 0.9978219866752625, \"C3422A\": null, \"A966C\": 1.0, \"G6661A\": null, \"G7731A\": null, \"T4026G\": null, \"T5260C\": null, \"T5287C\": null}",
|
|
36
|
+
"reference": "RSV-B"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"aminoAcidMutationFrequency": null,
|
|
40
|
+
"date": "2024-11-14",
|
|
41
|
+
"location": "Genève",
|
|
42
|
+
"nucleotideMutationFrequency": "{\"A12183T\": null, \"C2554T\": 0.9994590282440186, \"C3422A\": 0.05333299934864044, \"A966C\": 1.0, \"G6661A\": 0.9282640218734741, \"G7731A\": 0.9803630113601685, \"T4026G\": 0.0, \"T5260C\": 0.9970409870147705, \"T5287C\": 0.996694028377533}",
|
|
43
|
+
"reference": "RSV-B"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"aminoAcidMutationFrequency": null,
|
|
47
|
+
"date": "2024-11-13",
|
|
48
|
+
"location": "Laupen",
|
|
49
|
+
"nucleotideMutationFrequency": "{\"A12668G\": null, \"A3564G\": null, \"C10862T\": null, \"C12710T\": null, \"C3624T\": null, \"G11123A\": null, \"G3616A\": null, \"G7379A\": 0.9470750093460083, \"T11034A\": null, \"T3483C\": null}",
|
|
50
|
+
"reference": "RSV-A"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"aminoAcidMutationFrequency": null,
|
|
54
|
+
"date": "2024-11-13",
|
|
55
|
+
"location": "Zürich",
|
|
56
|
+
"nucleotideMutationFrequency": "{\"A12668G\": 0.9988809823989868, \"A3564G\": null, \"C10862T\": 1.0, \"C12710T\": 0.9991809725761414, \"C3624T\": null, \"G11123A\": 1.0, \"G3616A\": null, \"G7379A\": 0.9414680004119873, \"T11034A\": 0.9988250136375427, \"T3483C\": null}",
|
|
57
|
+
"reference": "RSV-A"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"aminoAcidMutationFrequency": null,
|
|
61
|
+
"date": "2024-11-16",
|
|
62
|
+
"location": "Zürich",
|
|
63
|
+
"nucleotideMutationFrequency": "{\"A12668G\": 0.999222993850708, \"A3564G\": 0.9998199939727783, \"C10862T\": 1.0, \"C12710T\": 0.9996299743652344, \"C3624T\": 0.9999099969863892, \"G11123A\": 1.0, \"G3616A\": 0.08799900114536285, \"G7379A\": null, \"T11034A\": 0.9970099925994873, \"T3483C\": 0.9993579983711243}",
|
|
64
|
+
"reference": "RSV-A"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"aminoAcidMutationFrequency": null,
|
|
68
|
+
"date": "2024-11-16",
|
|
69
|
+
"location": "Chur",
|
|
70
|
+
"nucleotideMutationFrequency": "{\"A12668G\": null, \"A3564G\": null, \"C10862T\": null, \"C12710T\": null, \"C3624T\": null, \"G11123A\": null, \"G3616A\": null, \"G7379A\": 0.6464089751243591, \"T11034A\": null, \"T3483C\": null}",
|
|
71
|
+
"reference": "RSV-A"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"aminoAcidMutationFrequency": null,
|
|
75
|
+
"date": "2024-11-18",
|
|
76
|
+
"location": "Basel",
|
|
77
|
+
"nucleotideMutationFrequency": "{\"A12668G\": null, \"A3564G\": 1.0, \"C10862T\": null, \"C12710T\": null, \"C3624T\": 1.0, \"G11123A\": null, \"G3616A\": 0.08222199976444244, \"G7379A\": null, \"T11034A\": null, \"T3483C\": 0.9998080134391785}",
|
|
78
|
+
"reference": "RSV-A"
|
|
79
|
+
}
|
|
80
|
+
],
|
|
81
|
+
"info": {
|
|
82
|
+
"dataVersion": "1737327031",
|
|
83
|
+
"requestId": "5591b455-3d84-438c-8434-2e57ee2ad569",
|
|
84
|
+
"requestInfo": "RSV on api.wise-loculus.genspectrum.org at 2025-01-20T11:58:03.498206810",
|
|
85
|
+
"reportTo": "Please report to https://github.com/GenSpectrum/LAPIS/issues in case you encounter any unexpected issues. Please include the request ID and the requestInfo in your report.",
|
|
86
|
+
"lapisVersion": "0.3.10"
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -8,6 +8,7 @@ import referenceGenome from '../../../lapisApi/__mockData__/referenceGenome.json
|
|
|
8
8
|
import { LapisUrlContextProvider } from '../../LapisUrlContext';
|
|
9
9
|
import { ReferenceGenomeContext } from '../../ReferenceGenomeContext';
|
|
10
10
|
import details from './__mockData__/details.json';
|
|
11
|
+
import detailsNonSegmented from './__mockData__/detailsAminAcidNonSegmented.json';
|
|
11
12
|
import type { MutationsOverTimeProps } from '../../mutationsOverTime/mutations-over-time';
|
|
12
13
|
import { playThatExpectsFinishedLoadingEvent } from '../../shared/stories/expectFinishedLoadingEvent';
|
|
13
14
|
|
|
@@ -113,6 +114,39 @@ export const AminoAcids: StoryObj<WastewaterMutationsOverTimeProps> = {
|
|
|
113
114
|
},
|
|
114
115
|
};
|
|
115
116
|
|
|
117
|
+
export const AminoAcidsNonSegmented: StoryObj<WastewaterMutationsOverTimeProps> = {
|
|
118
|
+
...Default,
|
|
119
|
+
args: {
|
|
120
|
+
...Default.args,
|
|
121
|
+
sequenceType: 'amino acid',
|
|
122
|
+
},
|
|
123
|
+
parameters: {
|
|
124
|
+
fetchMock: {
|
|
125
|
+
mocks: [
|
|
126
|
+
{
|
|
127
|
+
matcher: {
|
|
128
|
+
name: 'details',
|
|
129
|
+
url: WISE_DETAILS_ENDPOINT,
|
|
130
|
+
body: {
|
|
131
|
+
fields: ['date', 'location', 'nucleotideMutationFrequency', 'aminoAcidMutationFrequency'],
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
response: {
|
|
135
|
+
status: 200,
|
|
136
|
+
body: detailsNonSegmented,
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
],
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
play: async ({ canvas }) => {
|
|
143
|
+
await expectMutationOnPage(canvas, 'G204P');
|
|
144
|
+
await expectMutationOnPage(canvas, 'R346T');
|
|
145
|
+
await expectMutationOnPage(canvas, 'Q493E');
|
|
146
|
+
await expectMutationOnPage(canvas, 'S4286C');
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
|
|
116
150
|
export const UsesMutationFilter: StoryObj<MutationsOverTimeProps> = {
|
|
117
151
|
...Default,
|
|
118
152
|
play: async ({ canvas, step }) => {
|
|
@@ -295,17 +295,34 @@ async function queryMutationsOverTimeDataDirectEndpoint(
|
|
|
295
295
|
responseMutations.map((mutation, i) => [
|
|
296
296
|
mutation.code,
|
|
297
297
|
new Map(
|
|
298
|
-
allDates.map((date, j): [string, MutationOverTimeMutationValue] =>
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
298
|
+
allDates.map((date, j): [string, MutationOverTimeMutationValue] => {
|
|
299
|
+
if (totalCounts[j] === 0) {
|
|
300
|
+
return [date.dateString, null];
|
|
301
|
+
}
|
|
302
|
+
// 'count' in the API resp. is the number of seqs with the mutation
|
|
303
|
+
const count = apiResult.data.data[i][j].count;
|
|
304
|
+
// 'coverage' in the API resp. is the number of seqs. that have a non-ambiguous symbol at position
|
|
305
|
+
const coverage = apiResult.data.data[i][j].coverage;
|
|
306
|
+
const totalCount = totalCounts[j];
|
|
307
|
+
if (coverage === 0) {
|
|
308
|
+
return [
|
|
309
|
+
date.dateString,
|
|
310
|
+
{
|
|
311
|
+
type: 'belowThreshold',
|
|
312
|
+
totalCount,
|
|
313
|
+
},
|
|
314
|
+
];
|
|
315
|
+
}
|
|
316
|
+
return [
|
|
317
|
+
date.dateString,
|
|
318
|
+
{
|
|
319
|
+
type: 'value',
|
|
320
|
+
proportion: count / coverage,
|
|
321
|
+
count,
|
|
322
|
+
totalCount,
|
|
323
|
+
},
|
|
324
|
+
];
|
|
325
|
+
}),
|
|
309
326
|
),
|
|
310
327
|
]),
|
|
311
328
|
),
|
|
@@ -290,12 +290,12 @@ describe('queryMutationsOverTimeNewEndpoint', () => {
|
|
|
290
290
|
expect(mutationOverTimeData.getAsArray()).to.deep.equal([
|
|
291
291
|
[
|
|
292
292
|
{ type: 'value', proportion: 0.4, count: 4, totalCount: 11 },
|
|
293
|
-
|
|
293
|
+
null,
|
|
294
294
|
{ type: 'value', proportion: 0, count: 0, totalCount: 13 },
|
|
295
295
|
],
|
|
296
296
|
[
|
|
297
297
|
{ type: 'value', proportion: 0.1, count: 1, totalCount: 11 },
|
|
298
|
-
|
|
298
|
+
null,
|
|
299
299
|
{ type: 'value', proportion: 0.3, count: 3, totalCount: 13 },
|
|
300
300
|
],
|
|
301
301
|
]);
|
|
@@ -1013,8 +1013,8 @@ describe('queryMutationsOverTimeNewEndpoint', () => {
|
|
|
1013
1013
|
|
|
1014
1014
|
expect(mutationOverTimeData.getAsArray()).to.deep.equal([
|
|
1015
1015
|
[
|
|
1016
|
-
{ type: '
|
|
1017
|
-
{ type: '
|
|
1016
|
+
{ type: 'belowThreshold', totalCount: 11 },
|
|
1017
|
+
{ type: 'belowThreshold', totalCount: 12 },
|
|
1018
1018
|
],
|
|
1019
1019
|
[
|
|
1020
1020
|
{ type: 'value', proportion: 0.2, count: 2, totalCount: 11 },
|
|
@@ -1135,8 +1135,8 @@ describe('queryMutationsOverTimeNewEndpoint', () => {
|
|
|
1135
1135
|
|
|
1136
1136
|
expect(mutationOverTimeData.getAsArray()).to.deep.equal([
|
|
1137
1137
|
[
|
|
1138
|
-
{ type: '
|
|
1139
|
-
{ type: '
|
|
1138
|
+
{ type: 'belowThreshold', totalCount: 11 },
|
|
1139
|
+
{ type: 'belowThreshold', totalCount: 12 },
|
|
1140
1140
|
],
|
|
1141
1141
|
[
|
|
1142
1142
|
{ type: 'value', proportion: 0.2, count: 2, totalCount: 11 },
|
|
@@ -57,7 +57,7 @@ function transformMutations(input: unknown): { mutation: Substitution; proportio
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
return Object.entries(mutationFrequency.data).map(([key, value]) => {
|
|
60
|
-
const mutation = SubstitutionClass.parse(key);
|
|
60
|
+
const mutation = SubstitutionClass.parse(key, true);
|
|
61
61
|
if (mutation === null) {
|
|
62
62
|
throw new Error(`Failed to parse mutation: "${key}"`);
|
|
63
63
|
}
|
package/src/utils/mutations.ts
CHANGED
|
@@ -17,15 +17,19 @@ export interface MutationClass extends Mutation {
|
|
|
17
17
|
const nucleotideChars = 'ACGTRYKMSWBDHVN';
|
|
18
18
|
const aminoAcidChars = 'ACDEFGHIKLMNPQRSTVWY';
|
|
19
19
|
|
|
20
|
-
function segmentPart(
|
|
21
|
-
|
|
20
|
+
function segmentPart(isOptional: boolean) {
|
|
21
|
+
const segmentPart = `(?<segment>[A-Z0-9_-]+):`;
|
|
22
|
+
if (isOptional) {
|
|
23
|
+
return `(${segmentPart})?`;
|
|
24
|
+
}
|
|
25
|
+
return segmentPart;
|
|
22
26
|
}
|
|
23
27
|
|
|
24
|
-
function buildSubstitutionRegex(type: 'nucleotide' | 'aminoAcid') {
|
|
28
|
+
function buildSubstitutionRegex(type: 'nucleotide' | 'aminoAcid', segmentPartIsOptional: boolean) {
|
|
25
29
|
const chars = type === 'nucleotide' ? nucleotideChars : aminoAcidChars;
|
|
26
30
|
|
|
27
31
|
return new RegExp(
|
|
28
|
-
`^${segmentPart(
|
|
32
|
+
`^${segmentPart(segmentPartIsOptional)}` +
|
|
29
33
|
`(?<valueAtReference>[${chars}*])?` +
|
|
30
34
|
`(?<position>\\d+)` +
|
|
31
35
|
`(?<substitutionValue>[${chars}.*])?$`,
|
|
@@ -33,8 +37,9 @@ function buildSubstitutionRegex(type: 'nucleotide' | 'aminoAcid') {
|
|
|
33
37
|
);
|
|
34
38
|
}
|
|
35
39
|
|
|
36
|
-
const nucleotideSubstitutionRegex = buildSubstitutionRegex('nucleotide');
|
|
37
|
-
const aminoAcidSubstitutionRegex = buildSubstitutionRegex('aminoAcid');
|
|
40
|
+
const nucleotideSubstitutionRegex = buildSubstitutionRegex('nucleotide', true);
|
|
41
|
+
const aminoAcidSubstitutionRegex = buildSubstitutionRegex('aminoAcid', false);
|
|
42
|
+
const aminoAcidSubstitutionWithoutSegmentRegex = buildSubstitutionRegex('aminoAcid', true);
|
|
38
43
|
|
|
39
44
|
export interface Substitution extends Mutation {
|
|
40
45
|
type: 'substitution';
|
|
@@ -74,10 +79,13 @@ export class SubstitutionClass implements MutationClass, Substitution {
|
|
|
74
79
|
return this.code;
|
|
75
80
|
}
|
|
76
81
|
|
|
77
|
-
static parse(mutationStr: string): SubstitutionClass | null {
|
|
82
|
+
static parse(mutationStr: string, segmentIsOptional: boolean = false): SubstitutionClass | null {
|
|
78
83
|
const matchNucleotide = nucleotideSubstitutionRegex.exec(mutationStr);
|
|
79
84
|
const matchAminoAcid = aminoAcidSubstitutionRegex.exec(mutationStr);
|
|
80
|
-
const
|
|
85
|
+
const matchAminAcidWithoutSegment = segmentIsOptional
|
|
86
|
+
? aminoAcidSubstitutionWithoutSegmentRegex.exec(mutationStr)
|
|
87
|
+
: undefined;
|
|
88
|
+
const match = matchNucleotide ?? matchAminoAcid ?? matchAminAcidWithoutSegment;
|
|
81
89
|
if (match?.groups === undefined) {
|
|
82
90
|
return null;
|
|
83
91
|
}
|
|
@@ -94,7 +102,7 @@ function buildDeletionRegex(type: 'nucleotide' | 'aminoAcid') {
|
|
|
94
102
|
const chars = type === 'nucleotide' ? nucleotideChars : aminoAcidChars;
|
|
95
103
|
|
|
96
104
|
return new RegExp(
|
|
97
|
-
`^${segmentPart(type)}` + `(?<valueAtReference>[${chars}*])?` + `(?<position>\\d+)` + `(-)$`,
|
|
105
|
+
`^${segmentPart(type === 'nucleotide')}` + `(?<valueAtReference>[${chars}*])?` + `(?<position>\\d+)` + `(-)$`,
|
|
98
106
|
'i',
|
|
99
107
|
);
|
|
100
108
|
}
|
|
@@ -158,7 +166,7 @@ function buildInsertionRegex(type: 'nucleotide' | 'aminoAcid') {
|
|
|
158
166
|
const wildcardToken = `(?:\\.\\*)`;
|
|
159
167
|
|
|
160
168
|
return new RegExp(
|
|
161
|
-
`^ins_${segmentPart(type)}(?<position>\\d+):(?<insertedSymbols>(?:[${chars}?*]|${wildcardToken})+)$`,
|
|
169
|
+
`^ins_${segmentPart(type === 'nucleotide')}(?<position>\\d+):(?<insertedSymbols>(?:[${chars}?*]|${wildcardToken})+)$`,
|
|
162
170
|
'i',
|
|
163
171
|
);
|
|
164
172
|
}
|