@genspectrum/dashboard-components 0.1.1

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 (186) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +109 -0
  3. package/custom-elements.json +1587 -0
  4. package/dist/dashboard-components.js +7322 -0
  5. package/dist/dashboard-components.js.map +1 -0
  6. package/dist/genspectrum-components.d.ts +298 -0
  7. package/dist/style.css +2930 -0
  8. package/package.json +109 -0
  9. package/src/constants.ts +6 -0
  10. package/src/index.ts +1 -0
  11. package/src/lapisApi/ReferenceGenome.ts +30 -0
  12. package/src/lapisApi/__mockData__/referenceGenome.json +58 -0
  13. package/src/lapisApi/lapisApi.ts +99 -0
  14. package/src/lapisApi/lapisTypes.ts +51 -0
  15. package/src/operator/Dataset.ts +3 -0
  16. package/src/operator/DivisionOperator.spec.ts +27 -0
  17. package/src/operator/DivisionOperator.ts +60 -0
  18. package/src/operator/FetchAggregatedOperator.ts +44 -0
  19. package/src/operator/FetchInsertionsOperator.ts +24 -0
  20. package/src/operator/FetchSubstitutionsOrDeletionsOperator.ts +49 -0
  21. package/src/operator/FillMissingOperator.spec.ts +26 -0
  22. package/src/operator/FillMissingOperator.ts +30 -0
  23. package/src/operator/GroupByAndSumOperator.spec.ts +26 -0
  24. package/src/operator/GroupByAndSumOperator.ts +26 -0
  25. package/src/operator/GroupByOperator.spec.ts +43 -0
  26. package/src/operator/GroupByOperator.ts +32 -0
  27. package/src/operator/MapOperator.spec.ts +13 -0
  28. package/src/operator/MapOperator.ts +16 -0
  29. package/src/operator/MockOperator.spec.ts +11 -0
  30. package/src/operator/MockOperator.ts +12 -0
  31. package/src/operator/Operator.ts +5 -0
  32. package/src/operator/SlidingOperator.spec.ts +52 -0
  33. package/src/operator/SlidingOperator.ts +23 -0
  34. package/src/operator/SortOperator.spec.ts +13 -0
  35. package/src/operator/SortOperator.ts +16 -0
  36. package/src/preact/LapisUrlContext.ts +3 -0
  37. package/src/preact/ReferenceGenomeContext.ts +5 -0
  38. package/src/preact/components/SegmentSelector.tsx +62 -0
  39. package/src/preact/components/chart.stories.tsx +42 -0
  40. package/src/preact/components/chart.tsx +32 -0
  41. package/src/preact/components/checkbox-selector.stories.tsx +56 -0
  42. package/src/preact/components/checkbox-selector.tsx +46 -0
  43. package/src/preact/components/confidence-interval-selector.tsx +45 -0
  44. package/src/preact/components/csv-download-button.stories.tsx +25 -0
  45. package/src/preact/components/csv-download-button.tsx +51 -0
  46. package/src/preact/components/error-display.stories.tsx +22 -0
  47. package/src/preact/components/error-display.tsx +5 -0
  48. package/src/preact/components/headline.stories.tsx +29 -0
  49. package/src/preact/components/headline.tsx +16 -0
  50. package/src/preact/components/info.stories.tsx +22 -0
  51. package/src/preact/components/info.tsx +16 -0
  52. package/src/preact/components/loading-display.stories.tsx +20 -0
  53. package/src/preact/components/loading-display.tsx +5 -0
  54. package/src/preact/components/min-max-percent-slider.css +40 -0
  55. package/src/preact/components/min-max-range-slider.tsx +95 -0
  56. package/src/preact/components/mutation-type-selector.tsx +30 -0
  57. package/src/preact/components/no-data-display.stories.tsx +20 -0
  58. package/src/preact/components/no-data-display.tsx +5 -0
  59. package/src/preact/components/percent-intput.tsx +49 -0
  60. package/src/preact/components/proportion-selector-dropdown.stories.tsx +66 -0
  61. package/src/preact/components/proportion-selector-dropdown.tsx +33 -0
  62. package/src/preact/components/proportion-selector.stories.tsx +81 -0
  63. package/src/preact/components/proportion-selector.tsx +43 -0
  64. package/src/preact/components/scaling-selector.stories.tsx +25 -0
  65. package/src/preact/components/scaling-selector.tsx +36 -0
  66. package/src/preact/components/select.stories.tsx +42 -0
  67. package/src/preact/components/select.tsx +21 -0
  68. package/src/preact/components/table.stories.tsx +24 -0
  69. package/src/preact/components/table.tsx +51 -0
  70. package/src/preact/components/tabs.stories.tsx +60 -0
  71. package/src/preact/components/tabs.tsx +49 -0
  72. package/src/preact/dateRangeSelector/date-range-selector.stories.tsx +32 -0
  73. package/src/preact/dateRangeSelector/date-range-selector.tsx +228 -0
  74. package/src/preact/dateRangeSelector/dateConversion.ts +8 -0
  75. package/src/preact/locationFilter/__mockData__/aggregated.json +775 -0
  76. package/src/preact/locationFilter/fetchAutocompletionList.spec.ts +36 -0
  77. package/src/preact/locationFilter/fetchAutocompletionList.ts +43 -0
  78. package/src/preact/locationFilter/location-filter.stories.tsx +50 -0
  79. package/src/preact/locationFilter/location-filter.tsx +112 -0
  80. package/src/preact/mutationComparison/__mockData__/nucleotideMutationsOtherVariant.json +295 -0
  81. package/src/preact/mutationComparison/__mockData__/nucleotideMutationsSomeVariant.json +304 -0
  82. package/src/preact/mutationComparison/fetchMutationData.spec.ts +118 -0
  83. package/src/preact/mutationComparison/getMutationComparisonTableData.spec.ts +125 -0
  84. package/src/preact/mutationComparison/getMutationComparisonTableData.ts +40 -0
  85. package/src/preact/mutationComparison/mutation-comparison-table.tsx +43 -0
  86. package/src/preact/mutationComparison/mutation-comparison-venn.tsx +122 -0
  87. package/src/preact/mutationComparison/mutation-comparison.stories.tsx +152 -0
  88. package/src/preact/mutationComparison/mutation-comparison.tsx +179 -0
  89. package/src/preact/mutationComparison/queryMutationData.ts +53 -0
  90. package/src/preact/mutationFilter/mutation-filter.stories.tsx +164 -0
  91. package/src/preact/mutationFilter/mutation-filter.tsx +268 -0
  92. package/src/preact/mutationFilter/parseAndValidateMutation.ts +54 -0
  93. package/src/preact/mutationFilter/parseMutation.spec.ts +150 -0
  94. package/src/preact/mutationFilter/sequenceTypeFromSegment.spec.ts +66 -0
  95. package/src/preact/mutationFilter/sequenceTypeFromSegment.ts +20 -0
  96. package/src/preact/mutations/__mockData__/nucleotideInsertions.json +252 -0
  97. package/src/preact/mutations/__mockData__/nucleotideMutations.json +880 -0
  98. package/src/preact/mutations/getInsertionsTableData.spec.ts +36 -0
  99. package/src/preact/mutations/getInsertionsTableData.ts +10 -0
  100. package/src/preact/mutations/getMutationsGridData.spec.ts +135 -0
  101. package/src/preact/mutations/getMutationsGridData.ts +92 -0
  102. package/src/preact/mutations/getMutationsTableData.spec.ts +94 -0
  103. package/src/preact/mutations/getMutationsTableData.ts +17 -0
  104. package/src/preact/mutations/mutations-grid.tsx +84 -0
  105. package/src/preact/mutations/mutations-insertions-table.tsx +33 -0
  106. package/src/preact/mutations/mutations-table.tsx +47 -0
  107. package/src/preact/mutations/mutations.stories.tsx +95 -0
  108. package/src/preact/mutations/mutations.tsx +192 -0
  109. package/src/preact/mutations/queryMutations.ts +55 -0
  110. package/src/preact/prevalenceOverTime/__mockData__/denominator.json +1700 -0
  111. package/src/preact/prevalenceOverTime/__mockData__/denominatorOneVariant.json +608 -0
  112. package/src/preact/prevalenceOverTime/__mockData__/numeratorEG.json +1560 -0
  113. package/src/preact/prevalenceOverTime/__mockData__/numeratorJN1.json +592 -0
  114. package/src/preact/prevalenceOverTime/__mockData__/numeratorOneVariant.json +604 -0
  115. package/src/preact/prevalenceOverTime/getPrevalenceOverTimeTableData.spec.ts +67 -0
  116. package/src/preact/prevalenceOverTime/getPrevalenceOverTimeTableData.ts +18 -0
  117. package/src/preact/prevalenceOverTime/prevalence-over-time-bar-chart.tsx +105 -0
  118. package/src/preact/prevalenceOverTime/prevalence-over-time-bubble-chart.tsx +86 -0
  119. package/src/preact/prevalenceOverTime/prevalence-over-time-line-chart.tsx +141 -0
  120. package/src/preact/prevalenceOverTime/prevalence-over-time-table.tsx +46 -0
  121. package/src/preact/prevalenceOverTime/prevalence-over-time.stories.tsx +165 -0
  122. package/src/preact/prevalenceOverTime/prevalence-over-time.tsx +202 -0
  123. package/src/preact/relativeGrowthAdvantage/__mockData__/denominator.json +376 -0
  124. package/src/preact/relativeGrowthAdvantage/__mockData__/numerator.json +332 -0
  125. package/src/preact/relativeGrowthAdvantage/relative-growth-advantage-chart.tsx +138 -0
  126. package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.stories.tsx +71 -0
  127. package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.tsx +136 -0
  128. package/src/preact/shared/charts/LogitScale.ts +48 -0
  129. package/src/preact/shared/charts/colors.ts +26 -0
  130. package/src/preact/shared/charts/confideceInterval.ts +29 -0
  131. package/src/preact/shared/charts/getYAxisScale.ts +16 -0
  132. package/src/preact/shared/charts/scales.ts +16 -0
  133. package/src/preact/shared/icons/DeleteIcon.tsx +17 -0
  134. package/src/preact/shared/sort/sortInsertions.spec.ts +47 -0
  135. package/src/preact/shared/sort/sortInsertions.ts +21 -0
  136. package/src/preact/shared/sort/sortMutationPositions.spec.ts +31 -0
  137. package/src/preact/shared/sort/sortMutationPositions.ts +14 -0
  138. package/src/preact/shared/sort/sortSubstitutionsAndDeletions.spec.ts +47 -0
  139. package/src/preact/shared/sort/sortSubstitutionsAndDeletions.ts +17 -0
  140. package/src/preact/shared/table/formatProportion.ts +3 -0
  141. package/src/preact/textInput/__mockData__/aggregated_hosts.json +24 -0
  142. package/src/preact/textInput/fetchAutocompleteList.ts +9 -0
  143. package/src/preact/textInput/text-input.stories.tsx +49 -0
  144. package/src/preact/textInput/text-input.tsx +73 -0
  145. package/src/preact/useQuery.ts +27 -0
  146. package/src/query/queryInsertions.ts +14 -0
  147. package/src/query/queryPrevalenceOverTime.ts +126 -0
  148. package/src/query/queryRelativeGrowthAdvantage.ts +131 -0
  149. package/src/query/querySubstitutionsOrDeletions.ts +19 -0
  150. package/src/styles/tailwind.css +3 -0
  151. package/src/styles/tailwind.d.ts +3 -0
  152. package/src/types.ts +23 -0
  153. package/src/utils/mutations.spec.ts +64 -0
  154. package/src/utils/mutations.ts +165 -0
  155. package/src/utils/temporal.spec.ts +97 -0
  156. package/src/utils/temporal.ts +348 -0
  157. package/src/utils/test-utils.ts +5 -0
  158. package/src/utils/type-utils.ts +15 -0
  159. package/src/utils/utils.spec.ts +16 -0
  160. package/src/utils/utils.ts +38 -0
  161. package/src/web-components/PreactLitAdapter.tsx +62 -0
  162. package/src/web-components/PreactLitAdapterWithGridJsStyles.tsx +12 -0
  163. package/src/web-components/app.ts +51 -0
  164. package/src/web-components/display/index.ts +4 -0
  165. package/src/web-components/display/mutation-comparison-component.stories.ts +138 -0
  166. package/src/web-components/display/mutation-comparison-component.tsx +31 -0
  167. package/src/web-components/display/mutations-component.stories.ts +107 -0
  168. package/src/web-components/display/mutations-component.tsx +27 -0
  169. package/src/web-components/display/prevalence-over-time-component.stories.ts +205 -0
  170. package/src/web-components/display/prevalence-over-time-component.tsx +46 -0
  171. package/src/web-components/display/relative-growth-advantage-component.stories.ts +89 -0
  172. package/src/web-components/display/relative-growth-advantage-component.tsx +37 -0
  173. package/src/web-components/index.ts +3 -0
  174. package/src/web-components/input/date-range-selector-component.stories.ts +53 -0
  175. package/src/web-components/input/date-range-selector-component.tsx +33 -0
  176. package/src/web-components/input/index.ts +4 -0
  177. package/src/web-components/input/location-filter-component.stories.ts +184 -0
  178. package/src/web-components/input/location-filter-component.tsx +68 -0
  179. package/src/web-components/input/location-filter.mdx +25 -0
  180. package/src/web-components/input/mutation-filter-component.stories.ts +97 -0
  181. package/src/web-components/input/mutation-filter-component.tsx +27 -0
  182. package/src/web-components/input/text-input-component.stories.ts +92 -0
  183. package/src/web-components/input/text-input-component.tsx +30 -0
  184. package/src/web-components/lapis-context.ts +3 -0
  185. package/src/web-components/reference-genome-context.ts +5 -0
  186. package/src/web-components/withinShadowRoot.story.ts +34 -0
@@ -0,0 +1,304 @@
1
+ {
2
+ "info": {
3
+ "dataVersion": 1709685650
4
+ },
5
+ "data": [
6
+ {
7
+ "mutation": "C29400T",
8
+ "proportion": 3.0892801977139327e-4,
9
+ "count": 5,
10
+ "sequenceName": null,
11
+ "mutationFrom": "C",
12
+ "mutationTo": "T",
13
+ "position": 29400
14
+ },
15
+ {
16
+ "mutation": "G210T",
17
+ "proportion": 0.014548332115899683,
18
+ "count": 239,
19
+ "sequenceName": null,
20
+ "mutationFrom": "G",
21
+ "mutationTo": "T",
22
+ "position": 210
23
+ },
24
+ {
25
+ "mutation": "C241T",
26
+ "proportion": 0.9940932894897089,
27
+ "count": 16325,
28
+ "sequenceName": null,
29
+ "mutationFrom": "C",
30
+ "mutationTo": "T",
31
+ "position": 241
32
+ },
33
+ {
34
+ "mutation": "C3037T",
35
+ "proportion": 0.9993348249380177,
36
+ "count": 16526,
37
+ "sequenceName": null,
38
+ "mutationFrom": "C",
39
+ "mutationTo": "T",
40
+ "position": 3037
41
+ },
42
+ {
43
+ "mutation": "C12876T",
44
+ "proportion": 1.8133462282398453e-4,
45
+ "count": 3,
46
+ "sequenceName": null,
47
+ "mutationFrom": "C",
48
+ "mutationTo": "T",
49
+ "position": 12876
50
+ },
51
+ {
52
+ "mutation": "G4181T",
53
+ "proportion": 4.8443744701465424e-4,
54
+ "count": 8,
55
+ "sequenceName": null,
56
+ "mutationFrom": "G",
57
+ "mutationTo": "T",
58
+ "position": 4181
59
+ },
60
+ {
61
+ "mutation": "C15495T",
62
+ "proportion": 6.0240963855421684e-5,
63
+ "count": 1,
64
+ "sequenceName": null,
65
+ "mutationFrom": "C",
66
+ "mutationTo": "T",
67
+ "position": 15495
68
+ },
69
+ {
70
+ "mutation": "C6402T",
71
+ "proportion": 0.005873448380260369,
72
+ "count": 97,
73
+ "sequenceName": null,
74
+ "mutationFrom": "C",
75
+ "mutationTo": "T",
76
+ "position": 6402
77
+ },
78
+ {
79
+ "mutation": "C18664T",
80
+ "proportion": 1.2061998673180146e-4,
81
+ "count": 2,
82
+ "sequenceName": null,
83
+ "mutationFrom": "C",
84
+ "mutationTo": "T",
85
+ "position": 18664
86
+ },
87
+ {
88
+ "mutation": "C7124T",
89
+ "proportion": 4.30530782950981e-4,
90
+ "count": 7,
91
+ "sequenceName": null,
92
+ "mutationFrom": "C",
93
+ "mutationTo": "T",
94
+ "position": 7124
95
+ },
96
+ {
97
+ "mutation": "T8654C",
98
+ "proportion": 1.2232415902140674e-4,
99
+ "count": 2,
100
+ "sequenceName": null,
101
+ "mutationFrom": "T",
102
+ "mutationTo": "C",
103
+ "position": 8654
104
+ },
105
+ {
106
+ "mutation": "C8986T",
107
+ "proportion": 7.258210851025222e-4,
108
+ "count": 12,
109
+ "sequenceName": null,
110
+ "mutationFrom": "C",
111
+ "mutationTo": "T",
112
+ "position": 8986
113
+ },
114
+ {
115
+ "mutation": "G9053T",
116
+ "proportion": 4.836174585902551e-4,
117
+ "count": 8,
118
+ "sequenceName": null,
119
+ "mutationFrom": "G",
120
+ "mutationTo": "T",
121
+ "position": 9053
122
+ },
123
+ {
124
+ "mutation": "A28030G",
125
+ "proportion": 3.661662394727206e-4,
126
+ "count": 6,
127
+ "sequenceName": null,
128
+ "mutationFrom": "A",
129
+ "mutationTo": "G",
130
+ "position": 28030
131
+ },
132
+ {
133
+ "mutation": "C10029T",
134
+ "proportion": 1.2097749818533752e-4,
135
+ "count": 2,
136
+ "sequenceName": null,
137
+ "mutationFrom": "C",
138
+ "mutationTo": "T",
139
+ "position": 10029
140
+ },
141
+ {
142
+ "mutation": "A11201G",
143
+ "proportion": 1.8129079042784627e-4,
144
+ "count": 3,
145
+ "sequenceName": null,
146
+ "mutationFrom": "A",
147
+ "mutationTo": "G",
148
+ "position": 11201
149
+ },
150
+ {
151
+ "mutation": "A11332G",
152
+ "proportion": 1.8144429660094352e-4,
153
+ "count": 3,
154
+ "sequenceName": null,
155
+ "mutationFrom": "A",
156
+ "mutationTo": "G",
157
+ "position": 11332
158
+ },
159
+ {
160
+ "mutation": "C14408T",
161
+ "proportion": 0.9990330573517858,
162
+ "count": 16531,
163
+ "sequenceName": null,
164
+ "mutationFrom": "C",
165
+ "mutationTo": "T",
166
+ "position": 14408
167
+ },
168
+ {
169
+ "mutation": "G15451A",
170
+ "proportion": 9.048681908668637e-4,
171
+ "count": 15,
172
+ "sequenceName": null,
173
+ "mutationFrom": "G",
174
+ "mutationTo": "A",
175
+ "position": 15451
176
+ },
177
+ {
178
+ "mutation": "C16466T",
179
+ "proportion": 3.6175087423127937e-4,
180
+ "count": 6,
181
+ "sequenceName": null,
182
+ "mutationFrom": "C",
183
+ "mutationTo": "T",
184
+ "position": 16466
185
+ },
186
+ {
187
+ "mutation": "C21618G",
188
+ "proportion": 3.059975520195838e-4,
189
+ "count": 5,
190
+ "sequenceName": null,
191
+ "mutationFrom": "C",
192
+ "mutationTo": "G",
193
+ "position": 21618
194
+ },
195
+ {
196
+ "mutation": "T22917G",
197
+ "proportion": 6.888346170705743e-4,
198
+ "count": 11,
199
+ "sequenceName": null,
200
+ "mutationFrom": "T",
201
+ "mutationTo": "G",
202
+ "position": 22917
203
+ },
204
+ {
205
+ "mutation": "C22995A",
206
+ "proportion": 3.73366521468575e-4,
207
+ "count": 6,
208
+ "sequenceName": null,
209
+ "mutationFrom": "C",
210
+ "mutationTo": "A",
211
+ "position": 22995
212
+ },
213
+ {
214
+ "mutation": "A23403G",
215
+ "proportion": 0.9993967909277356,
216
+ "count": 16568,
217
+ "sequenceName": null,
218
+ "mutationFrom": "A",
219
+ "mutationTo": "G",
220
+ "position": 23403
221
+ },
222
+ {
223
+ "mutation": "C23604G",
224
+ "proportion": 0.001029616619223548,
225
+ "count": 17,
226
+ "sequenceName": null,
227
+ "mutationFrom": "C",
228
+ "mutationTo": "G",
229
+ "position": 23604
230
+ },
231
+ {
232
+ "mutation": "A25983T",
233
+ "proportion": 6.0379181258302136e-5,
234
+ "count": 1,
235
+ "sequenceName": null,
236
+ "mutationFrom": "A",
237
+ "mutationTo": "T",
238
+ "position": 25983
239
+ },
240
+ {
241
+ "mutation": "A17725C",
242
+ "proportion": 2.409058058299205e-4,
243
+ "count": 4,
244
+ "sequenceName": null,
245
+ "mutationFrom": "A",
246
+ "mutationTo": "C",
247
+ "position": 17725
248
+ },
249
+ {
250
+ "mutation": "G24410A",
251
+ "proportion": 6.027727546714888e-4,
252
+ "count": 10,
253
+ "sequenceName": null,
254
+ "mutationFrom": "G",
255
+ "mutationTo": "A",
256
+ "position": 24410
257
+ },
258
+ {
259
+ "mutation": "C25469T",
260
+ "proportion": 0.001087087812537746,
261
+ "count": 18,
262
+ "sequenceName": null,
263
+ "mutationFrom": "C",
264
+ "mutationTo": "T",
265
+ "position": 25469
266
+ },
267
+ {
268
+ "mutation": "C14214T",
269
+ "proportion": 2.414875633904854e-4,
270
+ "count": 4,
271
+ "sequenceName": null,
272
+ "mutationFrom": "C",
273
+ "mutationTo": "T",
274
+ "position": 14214
275
+ },
276
+ {
277
+ "mutation": "T26767C",
278
+ "proportion": 0.0013264198721813579,
279
+ "count": 22,
280
+ "sequenceName": null,
281
+ "mutationFrom": "T",
282
+ "mutationTo": "C",
283
+ "position": 26767
284
+ },
285
+ {
286
+ "mutation": "T1234C",
287
+ "proportion": 0.012345,
288
+ "count": 1234,
289
+ "sequenceName": null,
290
+ "mutationFrom": "T",
291
+ "mutationTo": "C",
292
+ "position": 1234
293
+ },
294
+ {
295
+ "mutation": "G199-",
296
+ "proportion": 6.128577557148986e-5,
297
+ "count": 1,
298
+ "sequenceName": null,
299
+ "mutationFrom": "G",
300
+ "mutationTo": "-",
301
+ "position": 199
302
+ }
303
+ ]
304
+ }
@@ -0,0 +1,118 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import { filterMutationData } from './queryMutationData';
4
+ import { type SubstitutionOrDeletion, type SubstitutionOrDeletionEntry } from '../../types';
5
+ import { Deletion, Substitution } from '../../utils/mutations';
6
+
7
+ const segment = 'testSegment';
8
+ const displayedSegment = { segment, label: 'label', checked: true };
9
+
10
+ describe('filterMutationData', () => {
11
+ function makeMutation({
12
+ segment,
13
+ type,
14
+ }: {
15
+ segment: string | undefined;
16
+ type: SubstitutionOrDeletion;
17
+ }): SubstitutionOrDeletionEntry {
18
+ switch (type) {
19
+ case 'substitution':
20
+ return {
21
+ type: 'substitution',
22
+ mutation: new Substitution(segment, 'A', 'B', 0),
23
+ count: 0,
24
+ proportion: 0,
25
+ };
26
+ case 'deletion':
27
+ return {
28
+ type: 'deletion',
29
+ mutation: new Deletion(segment, 'A', 0),
30
+ count: 0,
31
+ proportion: 0,
32
+ };
33
+ }
34
+ }
35
+
36
+ it('should filter deletions', () => {
37
+ const result = filterMutationData(
38
+ [
39
+ {
40
+ displayName: 'test',
41
+ data: [
42
+ makeMutation({ segment, type: 'substitution' }),
43
+ makeMutation({ segment, type: 'deletion' }),
44
+ ],
45
+ },
46
+ ],
47
+ [displayedSegment],
48
+ [
49
+ { type: 'deletion', label: 'label', checked: true },
50
+ { type: 'substitution', label: 'label', checked: false },
51
+ ],
52
+ );
53
+
54
+ expect(result[0].data).to.have.length(1);
55
+ expect(result[0].data[0].type).to.equal('deletion');
56
+ });
57
+
58
+ it('should filter substitutions', () => {
59
+ const result = filterMutationData(
60
+ [
61
+ {
62
+ displayName: 'test',
63
+ data: [
64
+ makeMutation({ segment, type: 'substitution' }),
65
+ makeMutation({ segment, type: 'deletion' }),
66
+ ],
67
+ },
68
+ ],
69
+ [displayedSegment],
70
+ [
71
+ { type: 'deletion', label: 'label', checked: false },
72
+ { type: 'substitution', label: 'label', checked: true },
73
+ ],
74
+ );
75
+
76
+ expect(result[0].data).to.have.length(1);
77
+ expect(result[0].data[0].type).to.equal('substitution');
78
+ });
79
+
80
+ it('should filter by segment', () => {
81
+ const otherSegment = 'otherSegment';
82
+ const result = filterMutationData(
83
+ [
84
+ {
85
+ displayName: 'test',
86
+ data: [
87
+ makeMutation({ segment, type: 'substitution' }),
88
+ makeMutation({ segment: otherSegment, type: 'substitution' }),
89
+ ],
90
+ },
91
+ ],
92
+ [
93
+ { segment, label: 'label', checked: true },
94
+ { segment: otherSegment, label: 'label', checked: false },
95
+ ],
96
+ [{ type: 'substitution', label: 'label', checked: true }],
97
+ );
98
+
99
+ expect(result[0].data).to.have.length(1);
100
+ expect(result[0].data[0].mutation.segment).to.equal(segment);
101
+ });
102
+
103
+ it('should never filter out undefined segments', () => {
104
+ const result = filterMutationData(
105
+ [
106
+ {
107
+ displayName: 'test',
108
+ data: [makeMutation({ segment: undefined, type: 'substitution' })],
109
+ },
110
+ ],
111
+ [{ segment, label: 'label', checked: false }],
112
+ [{ type: 'substitution', label: 'label', checked: true }],
113
+ );
114
+
115
+ expect(result[0].data).to.have.length(1);
116
+ expect(result[0].data[0].mutation.segment).to.equal(undefined);
117
+ });
118
+ });
@@ -0,0 +1,125 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import { getMutationComparisonTableData } from './getMutationComparisonTableData';
4
+ import { type MutationData } from './queryMutationData';
5
+ import { type Dataset } from '../../operator/Dataset';
6
+ import { type SubstitutionEntry } from '../../types';
7
+ import { Substitution } from '../../utils/mutations';
8
+
9
+ describe('getPrevalenceOverTimeTableData', () => {
10
+ it('should flatten the data to CSV format', () => {
11
+ const data: Dataset<MutationData> = {
12
+ content: [
13
+ {
14
+ displayName: 'Test 1',
15
+ data: [
16
+ {
17
+ type: 'substitution',
18
+ mutation: new Substitution(undefined, 'A', 'T', 123),
19
+ count: 1,
20
+ proportion: 0.123,
21
+ },
22
+ {
23
+ type: 'substitution',
24
+ mutation: new Substitution(undefined, 'G', 'A', 234),
25
+ count: 2,
26
+ proportion: 0.567,
27
+ },
28
+ ],
29
+ },
30
+ {
31
+ displayName: 'Test 2',
32
+ data: [
33
+ {
34
+ type: 'substitution',
35
+ mutation: new Substitution(undefined, 'A', 'T', 123),
36
+ count: 3,
37
+ proportion: 0.345,
38
+ },
39
+ {
40
+ type: 'substitution',
41
+ mutation: new Substitution(undefined, 'G', 'A', 234),
42
+ count: 4,
43
+ proportion: 0.789,
44
+ },
45
+ ],
46
+ },
47
+ ],
48
+ };
49
+
50
+ const result = getMutationComparisonTableData(data, { min: 0, max: 1 });
51
+
52
+ expect(result).toEqual([
53
+ {
54
+ mutation: 'A123T',
55
+ 'Test 1 prevalence': 0.123,
56
+ 'Test 2 prevalence': 0.345,
57
+ },
58
+ {
59
+ mutation: 'G234A',
60
+ 'Test 1 prevalence': 0.567,
61
+ 'Test 2 prevalence': 0.789,
62
+ },
63
+ ]);
64
+ });
65
+
66
+ it('should filter out when no proportion value is in interval', () => {
67
+ function makeSubstitutionWithProportionAtPosition(proportion: number, position: number): SubstitutionEntry {
68
+ return {
69
+ type: 'substitution',
70
+ mutation: new Substitution(undefined, 'A', 'T', position),
71
+ count: 1,
72
+ proportion,
73
+ };
74
+ }
75
+
76
+ const belowRange = 0.1;
77
+ const inRange = 0.2;
78
+ const aboveRange = 0.3;
79
+
80
+ const data: Dataset<MutationData> = {
81
+ content: [
82
+ {
83
+ displayName: 'Test 1',
84
+ data: [
85
+ makeSubstitutionWithProportionAtPosition(belowRange, 100),
86
+ makeSubstitutionWithProportionAtPosition(inRange, 200),
87
+ makeSubstitutionWithProportionAtPosition(inRange, 300),
88
+ makeSubstitutionWithProportionAtPosition(inRange, 400),
89
+ makeSubstitutionWithProportionAtPosition(aboveRange, 500),
90
+ ],
91
+ },
92
+ {
93
+ displayName: 'Test 2',
94
+ data: [
95
+ makeSubstitutionWithProportionAtPosition(belowRange, 100),
96
+ makeSubstitutionWithProportionAtPosition(belowRange, 200),
97
+ makeSubstitutionWithProportionAtPosition(inRange, 300),
98
+ makeSubstitutionWithProportionAtPosition(aboveRange, 400),
99
+ makeSubstitutionWithProportionAtPosition(aboveRange, 500),
100
+ ],
101
+ },
102
+ ],
103
+ };
104
+
105
+ const result = getMutationComparisonTableData(data, { min: 0.15, max: 0.25 });
106
+
107
+ expect(result).toEqual([
108
+ {
109
+ mutation: 'A200T',
110
+ 'Test 1 prevalence': inRange,
111
+ 'Test 2 prevalence': belowRange,
112
+ },
113
+ {
114
+ mutation: 'A300T',
115
+ 'Test 1 prevalence': inRange,
116
+ 'Test 2 prevalence': inRange,
117
+ },
118
+ {
119
+ mutation: 'A400T',
120
+ 'Test 1 prevalence': inRange,
121
+ 'Test 2 prevalence': aboveRange,
122
+ },
123
+ ]);
124
+ });
125
+ });
@@ -0,0 +1,40 @@
1
+ import { type MutationData } from './queryMutationData';
2
+ import { type Dataset } from '../../operator/Dataset';
3
+ import { type ProportionInterval } from '../components/proportion-selector';
4
+
5
+ type Proportions = {
6
+ [displayName: string]: number;
7
+ };
8
+
9
+ export function getMutationComparisonTableData(data: Dataset<MutationData>, proportionInterval: ProportionInterval) {
10
+ const mutationsToProportions = new Map<string, Proportions>();
11
+
12
+ for (const mutationData of data.content) {
13
+ for (const mutationEntry of mutationData.data) {
14
+ const mutation = mutationEntry.mutation.toString();
15
+ const proportions = mutationsToProportions.get(mutation) || {};
16
+ proportions[mutationData.displayName] = mutationEntry.proportion;
17
+ mutationsToProportions.set(mutation, proportions);
18
+ }
19
+ }
20
+
21
+ return [...mutationsToProportions.entries()]
22
+ .map(([mutation, proportions]) => {
23
+ return {
24
+ mutation,
25
+ ...data.content
26
+ .map((mutationData) => {
27
+ return {
28
+ [`${mutationData.displayName} prevalence`]: proportions[mutationData.displayName] || 0,
29
+ };
30
+ })
31
+ .reduce((acc, val) => ({ ...acc, ...val }), {}),
32
+ } as { mutation: string } & Proportions;
33
+ })
34
+ .filter((row) =>
35
+ Object.values(row).some(
36
+ (value) =>
37
+ typeof value === 'number' && value >= proportionInterval.min && value <= proportionInterval.max,
38
+ ),
39
+ );
40
+ }
@@ -0,0 +1,43 @@
1
+ import { type FunctionComponent } from 'preact';
2
+
3
+ import { getMutationComparisonTableData } from './getMutationComparisonTableData';
4
+ import { type MutationData } from './queryMutationData';
5
+ import { type Dataset } from '../../operator/Dataset';
6
+ import { type ProportionInterval } from '../components/proportion-selector';
7
+ import { Table } from '../components/table';
8
+ import { sortSubstitutionsAndDeletions } from '../shared/sort/sortSubstitutionsAndDeletions';
9
+ import { formatProportion } from '../shared/table/formatProportion';
10
+
11
+ export interface MutationsTableProps {
12
+ data: Dataset<MutationData>;
13
+ proportionInterval: ProportionInterval;
14
+ }
15
+
16
+ export const MutationComparisonTable: FunctionComponent<MutationsTableProps> = ({ data, proportionInterval }) => {
17
+ const getHeaders = () => {
18
+ return [
19
+ {
20
+ name: 'Mutation',
21
+ sort: {
22
+ compare: (a: string, b: string) => {
23
+ return sortSubstitutionsAndDeletions(a, b);
24
+ },
25
+ },
26
+ },
27
+ {
28
+ name: 'Prevalence',
29
+ columns: data.content.map((mutationData) => {
30
+ return {
31
+ name: mutationData.displayName,
32
+ sort: true,
33
+ formatter: (cell: number) => formatProportion(cell),
34
+ };
35
+ }),
36
+ },
37
+ ];
38
+ };
39
+
40
+ const tableData = getMutationComparisonTableData(data, proportionInterval).map((row) => Object.values(row));
41
+
42
+ return <Table data={tableData} columns={getHeaders()} pagination={true} />;
43
+ };