@genspectrum/dashboard-components 0.6.2 → 0.6.3

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 (39) hide show
  1. package/custom-elements.json +220 -0
  2. package/dist/dashboard-components.js +602 -178
  3. package/dist/dashboard-components.js.map +1 -1
  4. package/dist/genspectrum-components.d.ts +63 -0
  5. package/dist/style.css +7 -4
  6. package/package.json +3 -1
  7. package/src/constants.ts +1 -1
  8. package/src/lapisApi/lapisTypes.ts +1 -0
  9. package/src/operator/FillMissingOperator.spec.ts +3 -1
  10. package/src/operator/FillMissingOperator.ts +4 -2
  11. package/src/preact/mutationComparison/queryMutationData.ts +12 -4
  12. package/src/preact/mutationsOverTime/__mockData__/aggregated_date.json +642 -0
  13. package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_01.json +1747 -0
  14. package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_02.json +1774 -0
  15. package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_03.json +1819 -0
  16. package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_04.json +1864 -0
  17. package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_05.json +1927 -0
  18. package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_06.json +1864 -0
  19. package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_07.json +9 -0
  20. package/src/preact/mutationsOverTime/getFilteredMutationsOverTime.spec.ts +86 -0
  21. package/src/preact/mutationsOverTime/getFilteredMutationsOverTimeData.ts +62 -0
  22. package/src/preact/mutationsOverTime/mutations-over-time-grid.tsx +92 -0
  23. package/src/preact/mutationsOverTime/mutations-over-time.stories.tsx +206 -0
  24. package/src/preact/mutationsOverTime/mutations-over-time.tsx +170 -0
  25. package/src/preact/numberSequencesOverTime/getNumberOfSequencesOverTimeTableData.ts +1 -1
  26. package/src/preact/prevalenceOverTime/prevalence-over-time.stories.tsx +1 -0
  27. package/src/preact/shared/table/formatProportion.ts +2 -2
  28. package/src/query/queryAggregatedDataOverTime.ts +8 -33
  29. package/src/query/queryMutationsOverTime.spec.ts +352 -0
  30. package/src/query/queryMutationsOverTime.ts +164 -0
  31. package/src/query/queryNumberOfSequencesOverTime.ts +0 -1
  32. package/src/query/queryRelativeGrowthAdvantage.ts +3 -3
  33. package/src/utils/Map2d.ts +75 -0
  34. package/src/utils/map2d.spec.ts +94 -0
  35. package/src/utils/mutations.ts +5 -1
  36. package/src/utils/temporal.ts +64 -5
  37. package/src/web-components/visualization/gs-mutations-over-time.stories.ts +225 -0
  38. package/src/web-components/visualization/gs-mutations-over-time.tsx +107 -0
  39. package/src/web-components/visualization/index.ts +1 -0
@@ -0,0 +1,94 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import { Map2d } from './Map2d';
4
+
5
+ describe('Map2d', () => {
6
+ it('should add a value and return it', () => {
7
+ const map2d = new Map2d<string, string, number>();
8
+ map2d.set('a', 'b', 2);
9
+ expect(map2d.get('a', 'b')).toBe(2);
10
+ });
11
+
12
+ it('should update a value', () => {
13
+ const map2d = new Map2d<string, string, number>();
14
+ map2d.set('a', 'b', 2);
15
+ map2d.set('a', 'b', 3);
16
+ expect(map2d.get('a', 'b')).toBe(3);
17
+ });
18
+
19
+ it('should return the data as an array', () => {
20
+ const map2d = new Map2d<string, string, number>();
21
+ map2d.set('a', 'b', 1);
22
+ map2d.set('a', 'd', 2);
23
+ map2d.set('c', 'b', 3);
24
+ map2d.set('c', 'd', 4);
25
+
26
+ expect(map2d.getAsArray(0)).toEqual([
27
+ [1, 2],
28
+ [3, 4],
29
+ ]);
30
+ });
31
+
32
+ it('should fill empty values with the given value', () => {
33
+ const map2d = new Map2d<string, string, number>();
34
+ map2d.set('a', 'b', 2);
35
+ map2d.set('c', 'd', 4);
36
+ expect(map2d.getAsArray(0)).toEqual([
37
+ [2, 0],
38
+ [0, 4],
39
+ ]);
40
+ });
41
+
42
+ it('should return the keys from the first axis', () => {
43
+ const map2d = new Map2d<string, string, number>();
44
+ map2d.set('a', 'b', 2);
45
+ map2d.set('c', 'd', 4);
46
+
47
+ expect(map2d.getFirstAxisKeys()).toEqual(['a', 'c']);
48
+ });
49
+
50
+ it('should return the keys from the second axis', () => {
51
+ const map2d = new Map2d<string, string, number>();
52
+ map2d.set('a', 'b', 2);
53
+ map2d.set('c', 'd', 4);
54
+
55
+ expect(map2d.getSecondAxisKeys()).toEqual(['b', 'd']);
56
+ });
57
+
58
+ it('should work with objects as keys', () => {
59
+ const map2d = new Map2d<{ a: string }, { b: string }, number>();
60
+ map2d.set({ a: 'a' }, { b: 'b' }, 2);
61
+ map2d.set({ a: 'second' }, { b: 'second' }, 3);
62
+
63
+ expect(map2d.get({ a: 'a' }, { b: 'b' })).toBe(2);
64
+ expect(map2d.get({ a: 'second' }, { b: 'second' })).toBe(3);
65
+ });
66
+
67
+ it('should update a value with objects as keys', () => {
68
+ const map2d = new Map2d<{ a: string }, { b: string }, number>();
69
+ map2d.set({ a: 'a' }, { b: 'b' }, 2);
70
+ map2d.set({ a: 'a' }, { b: 'b' }, 3);
71
+ expect(map2d.get({ a: 'a' }, { b: 'b' })).toBe(3);
72
+ });
73
+
74
+ it('should create a deep copy of the map', () => {
75
+ const map2d = new Map2d<string, string, number>();
76
+ map2d.set('a', 'b', 2);
77
+ expect(map2d.get('a', 'b')).toBe(2);
78
+
79
+ const copy = map2d.copy();
80
+ expect(copy.get('a', 'b')).toBe(2);
81
+
82
+ map2d.deleteRow('a');
83
+ expect(map2d.get('a', 'b')).toBe(undefined);
84
+ });
85
+
86
+ it('should return a row by key', () => {
87
+ const map2d = new Map2d<string, string, number>();
88
+ map2d.set('a', 'b', 2);
89
+ map2d.set('c', 'd', 4);
90
+
91
+ expect(map2d.getRow('a', 0)).toEqual([2, 0]);
92
+ expect(map2d.getRow('c', 0)).toEqual([0, 4]);
93
+ });
94
+ });
@@ -1,9 +1,10 @@
1
- import { type SequenceType } from '../types';
1
+ import { type MutationType, type SequenceType } from '../types';
2
2
 
3
3
  export interface Mutation {
4
4
  readonly segment: string | undefined;
5
5
  readonly position: number;
6
6
  readonly code: string;
7
+ readonly type: MutationType;
7
8
 
8
9
  equals(other: Mutation): boolean;
9
10
 
@@ -15,6 +16,7 @@ export const substitutionRegex =
15
16
 
16
17
  export class Substitution implements Mutation {
17
18
  readonly code;
19
+ readonly type = 'substitution';
18
20
 
19
21
  constructor(
20
22
  readonly segment: string | undefined,
@@ -62,6 +64,7 @@ export const deletionRegex = /^((?<segment>[A-Za-z0-9_-]+)(?=:):)?(?<valueAtRefe
62
64
 
63
65
  export class Deletion implements Mutation {
64
66
  readonly code;
67
+ readonly type = 'deletion';
65
68
 
66
69
  constructor(
67
70
  readonly segment: string | undefined,
@@ -103,6 +106,7 @@ export const insertionRegexp =
103
106
 
104
107
  export class Insertion implements Mutation {
105
108
  readonly code;
109
+ readonly type = 'insertion';
106
110
 
107
111
  constructor(
108
112
  readonly segment: string | undefined,
@@ -2,6 +2,8 @@ import dayjs from 'dayjs/esm';
2
2
  import advancedFormat from 'dayjs/esm/plugin/advancedFormat';
3
3
  import isoWeek from 'dayjs/esm/plugin/isoWeek';
4
4
 
5
+ import type { TemporalGranularity } from '../types';
6
+
5
7
  dayjs.extend(isoWeek);
6
8
  dayjs.extend(advancedFormat);
7
9
 
@@ -70,6 +72,14 @@ export class YearMonthDay {
70
72
  return this.text;
71
73
  }
72
74
 
75
+ get firstDay(): YearMonthDay {
76
+ return this;
77
+ }
78
+
79
+ get lastDay(): YearMonthDay {
80
+ return this;
81
+ }
82
+
73
83
  get year(): Year {
74
84
  return this.cache.getYear(`${this.yearNumber}`);
75
85
  }
@@ -124,6 +134,16 @@ export class YearWeek {
124
134
  return this.cache.getYearMonthDay(firstDay.format('YYYY-MM-DD'));
125
135
  }
126
136
 
137
+ get lastDay(): YearMonthDay {
138
+ const lastDay = dayjs()
139
+ .year(this.isoYearNumber)
140
+ .month(12)
141
+ .date(31)
142
+ .isoWeek(this.isoWeekNumber)
143
+ .endOf('isoWeek');
144
+ return this.cache.getYearMonthDay(lastDay.format('YYYY-MM-DD'));
145
+ }
146
+
127
147
  get year(): Year {
128
148
  return this.cache.getYear(`${this.isoYearNumber}`);
129
149
  }
@@ -163,6 +183,12 @@ export class YearMonth {
163
183
  return this.cache.getYearMonthDay(dayjs(`${this.yearNumber}-${this.monthNumber}-01`).format('YYYY-MM-DD'));
164
184
  }
165
185
 
186
+ get lastDay(): YearMonthDay {
187
+ return this.cache.getYearMonthDay(
188
+ dayjs(`${this.yearNumber}-${this.monthNumber}-01`).endOf('month').format('YYYY-MM-DD'),
189
+ );
190
+ }
191
+
166
192
  get year(): Year {
167
193
  return this.cache.getYear(`${this.yearNumber}`);
168
194
  }
@@ -201,10 +227,18 @@ export class Year {
201
227
  return this.cache.getYearMonth(`${this.year}-01`);
202
228
  }
203
229
 
230
+ get lastMonth(): YearMonth {
231
+ return this.cache.getYearMonth(`${this.year}-12`);
232
+ }
233
+
204
234
  get firstDay(): YearMonthDay {
205
235
  return this.firstMonth.firstDay;
206
236
  }
207
237
 
238
+ get lastDay(): YearMonthDay {
239
+ return this.lastMonth.lastDay;
240
+ }
241
+
208
242
  addYears(years: number): Year {
209
243
  const date = this.firstDay.dayjs.add(years, 'year');
210
244
  const s = date.format('YYYY');
@@ -311,9 +345,9 @@ export function compareTemporal(a: Temporal | null, b: Temporal | null): number
311
345
  return 0;
312
346
  }
313
347
 
314
- export function getMinMaxTemporal(values: Iterable<Temporal | null>): [Temporal, Temporal] | null {
315
- let min = null;
316
- let max = null;
348
+ export function getMinMaxTemporal<T extends Temporal>(values: Iterable<T | null>) {
349
+ let min: T | null = null;
350
+ let max: T | null = null;
317
351
  for (const value of values) {
318
352
  if (value === null) {
319
353
  continue;
@@ -326,9 +360,9 @@ export function getMinMaxTemporal(values: Iterable<Temporal | null>): [Temporal,
326
360
  }
327
361
  }
328
362
  if (min === null || max === null) {
329
- return null;
363
+ return { min: null, max: null };
330
364
  }
331
- return [min, max];
365
+ return { min, max };
332
366
  }
333
367
 
334
368
  export function addUnit(temporal: Temporal, amount: number): Temporal {
@@ -346,3 +380,28 @@ export function addUnit(temporal: Temporal, amount: number): Temporal {
346
380
  }
347
381
  throw new Error(`Invalid argument: ${temporal}`);
348
382
  }
383
+
384
+ export function parseDateStringToTemporal(date: string, granularity: TemporalGranularity) {
385
+ const cache = TemporalCache.getInstance();
386
+ const day = cache.getYearMonthDay(date);
387
+ switch (granularity) {
388
+ case 'day':
389
+ return day;
390
+ case 'week':
391
+ return day.week;
392
+ case 'month':
393
+ return day.month;
394
+ case 'year':
395
+ return day.year;
396
+ }
397
+ }
398
+
399
+ export function dateRangeCompare(a: { dateRange: Temporal | null }, b: { dateRange: Temporal | null }) {
400
+ if (a.dateRange === null) {
401
+ return 1;
402
+ }
403
+ if (b.dateRange === null) {
404
+ return -1;
405
+ }
406
+ return compareTemporal(a.dateRange, b.dateRange);
407
+ }
@@ -0,0 +1,225 @@
1
+ import type { Meta, StoryObj } from '@storybook/web-components';
2
+ import { html } from 'lit';
3
+
4
+ import './gs-mutations-over-time';
5
+ import '../app';
6
+ import { withComponentDocs } from '../../../.storybook/ComponentDocsBlock';
7
+ import { AGGREGATED_ENDPOINT, LAPIS_URL, NUCLEOTIDE_MUTATIONS_ENDPOINT } from '../../constants';
8
+ import aggregated_date from '../../preact/mutationsOverTime/__mockData__/aggregated_date.json';
9
+ import nucleotideMutation_01 from '../../preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_01.json';
10
+ import nucleotideMutation_02 from '../../preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_02.json';
11
+ import nucleotideMutation_03 from '../../preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_03.json';
12
+ import nucleotideMutation_04 from '../../preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_04.json';
13
+ import nucleotideMutation_05 from '../../preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_05.json';
14
+ import nucleotideMutation_06 from '../../preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_06.json';
15
+ import nucleotideMutation_07 from '../../preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_07.json';
16
+ import { type MutationsOverTimeProps } from '../../preact/mutationsOverTime/mutations-over-time';
17
+
18
+ const codeExample = String.raw`
19
+ <gs-mutations-over-time
20
+ lapisFilter='{ "pangoLineage": "JN.1*", "dateFrom": "2024-01-15", "dateTo": "2024-07-10" }'
21
+ sequenceType="nucleotide"
22
+ views='["grid"]'
23
+ headline="Mutations over time"
24
+ width='100%'
25
+ height='700px'
26
+ granularity="month"
27
+ lapisDateField="date"
28
+ ></gs-mutations-over-time>`;
29
+
30
+ const meta: Meta<Required<MutationsOverTimeProps>> = {
31
+ title: 'Visualization/Mutations over time',
32
+ component: 'gs-mutations-over-time',
33
+ argTypes: {
34
+ lapisFilter: { control: 'object' },
35
+ sequenceType: {
36
+ options: ['nucleotide', 'amino acid'],
37
+ control: { type: 'radio' },
38
+ },
39
+ views: {
40
+ options: ['grid'],
41
+ control: { type: 'check' },
42
+ },
43
+ width: { control: 'text' },
44
+ height: { control: 'text' },
45
+ granularity: {
46
+ options: ['day', 'week', 'month', 'year'],
47
+ control: { type: 'radio' },
48
+ },
49
+ lapisDateField: { control: 'text' },
50
+ },
51
+ args: {
52
+ lapisFilter: { pangoLineage: 'JN.1*', dateFrom: '2024-01-15', dateTo: '2024-07-10' },
53
+ sequenceType: 'nucleotide',
54
+ views: ['grid'],
55
+ width: '100%',
56
+ height: '700px',
57
+ granularity: 'month',
58
+ lapisDateField: 'date',
59
+ },
60
+ parameters: withComponentDocs({
61
+ componentDocs: {
62
+ opensShadowDom: true,
63
+ expectsChildren: false,
64
+ codeExample,
65
+ },
66
+ }),
67
+ tags: ['autodocs'],
68
+ };
69
+
70
+ export default meta;
71
+
72
+ const Template: StoryObj<Required<MutationsOverTimeProps>> = {
73
+ render: (args) => html`
74
+ <gs-app lapis="${LAPIS_URL}">
75
+ <gs-mutations-over-time
76
+ .lapisFilter=${args.lapisFilter}
77
+ .sequenceType=${args.sequenceType}
78
+ .views=${args.views}
79
+ .width=${args.width}
80
+ .height=${args.height}
81
+ .granularity=${args.granularity}
82
+ .lapisDateField=${args.lapisDateField}
83
+ ></gs-mutations-over-time>
84
+ </gs-app>
85
+ `,
86
+ };
87
+
88
+ export const Default: StoryObj<Required<MutationsOverTimeProps>> = {
89
+ ...Template,
90
+ parameters: {
91
+ fetchMock: {
92
+ mocks: [
93
+ {
94
+ matcher: {
95
+ name: 'aggregated_dates',
96
+ url: AGGREGATED_ENDPOINT,
97
+ body: {
98
+ dateFrom: '2024-01-15',
99
+ dateTo: '2024-07-10',
100
+ fields: ['date'],
101
+ pangoLineage: 'JN.1*',
102
+ },
103
+ },
104
+ response: {
105
+ status: 200,
106
+ body: aggregated_date,
107
+ },
108
+ },
109
+ {
110
+ matcher: {
111
+ name: 'nucleotideMutations_01',
112
+ url: NUCLEOTIDE_MUTATIONS_ENDPOINT,
113
+ body: {
114
+ pangoLineage: 'JN.1*',
115
+ dateFrom: '2024-01-01',
116
+ dateTo: '2024-01-31',
117
+ minProportion: 0.001,
118
+ },
119
+ },
120
+ response: {
121
+ status: 200,
122
+ body: nucleotideMutation_01,
123
+ },
124
+ },
125
+ {
126
+ matcher: {
127
+ name: 'nucleotideMutations_02',
128
+ url: NUCLEOTIDE_MUTATIONS_ENDPOINT,
129
+ body: {
130
+ pangoLineage: 'JN.1*',
131
+ dateFrom: '2024-02-01',
132
+ dateTo: '2024-02-29',
133
+ minProportion: 0.001,
134
+ },
135
+ },
136
+ response: {
137
+ status: 200,
138
+ body: nucleotideMutation_02,
139
+ },
140
+ },
141
+ {
142
+ matcher: {
143
+ name: 'nucleotideMutations_03',
144
+ url: NUCLEOTIDE_MUTATIONS_ENDPOINT,
145
+ body: {
146
+ pangoLineage: 'JN.1*',
147
+ dateFrom: '2024-03-01',
148
+ dateTo: '2024-03-31',
149
+ minProportion: 0.001,
150
+ },
151
+ response: {
152
+ status: 200,
153
+ body: nucleotideMutation_03,
154
+ },
155
+ },
156
+ },
157
+ {
158
+ matcher: {
159
+ name: 'nucleotideMutations_04',
160
+ url: NUCLEOTIDE_MUTATIONS_ENDPOINT,
161
+ body: {
162
+ pangoLineage: 'JN.1*',
163
+ dateFrom: '2024-04-01',
164
+ dateTo: '2024-04-30',
165
+ minProportion: 0.001,
166
+ },
167
+ response: {
168
+ status: 200,
169
+ body: nucleotideMutation_04,
170
+ },
171
+ },
172
+ },
173
+ {
174
+ matcher: {
175
+ name: 'nucleotideMutations_05',
176
+ url: NUCLEOTIDE_MUTATIONS_ENDPOINT,
177
+ body: {
178
+ pangoLineage: 'JN.1*',
179
+ dateFrom: '2024-05-01',
180
+ dateTo: '2024-05-31',
181
+ minProportion: 0.001,
182
+ },
183
+ response: {
184
+ status: 200,
185
+ body: nucleotideMutation_05,
186
+ },
187
+ },
188
+ },
189
+ {
190
+ matcher: {
191
+ name: 'nucleotideMutations_06',
192
+ url: NUCLEOTIDE_MUTATIONS_ENDPOINT,
193
+ body: {
194
+ pangoLineage: 'JN.1*',
195
+ dateFrom: '2024-06-01',
196
+ dateTo: '2024-06-30',
197
+ minProportion: 0.001,
198
+ },
199
+ response: {
200
+ status: 200,
201
+ body: nucleotideMutation_06,
202
+ },
203
+ },
204
+ },
205
+
206
+ {
207
+ matcher: {
208
+ name: 'nucleotideMutations_07',
209
+ url: NUCLEOTIDE_MUTATIONS_ENDPOINT,
210
+ body: {
211
+ pangoLineage: 'JN.1*',
212
+ dateFrom: '2024-07-01',
213
+ dateTo: '2024-07-31',
214
+ minProportion: 0.001,
215
+ },
216
+ response: {
217
+ status: 200,
218
+ body: nucleotideMutation_07,
219
+ },
220
+ },
221
+ },
222
+ ],
223
+ },
224
+ },
225
+ };
@@ -0,0 +1,107 @@
1
+ import { customElement, property } from 'lit/decorators.js';
2
+
3
+ import { MutationsOverTime, type MutationsOverTimeProps } from '../../preact/mutationsOverTime/mutations-over-time';
4
+ import type { Equals, Expect } from '../../utils/typeAssertions';
5
+ import { PreactLitAdapterWithGridJsStyles } from '../PreactLitAdapterWithGridJsStyles';
6
+
7
+ /**
8
+ * ## Context
9
+ *
10
+ * This component displays mutations (substitutions and deletions) over time for a dataset selected by a LAPIS filter.
11
+ * The shown date range is determined by the date field in the LAPIS filter.
12
+ * If the date field is not set, the date range is determined by all available dates in the dataset.
13
+ *
14
+ * ## Views
15
+ *
16
+ * ### Grid View
17
+ *
18
+ * The grid view shows the proportion for each mutation over date ranges.
19
+ *
20
+ */
21
+ @customElement('gs-mutations-over-time')
22
+ export class MutationsOverTimeComponent extends PreactLitAdapterWithGridJsStyles {
23
+ /**
24
+ * Required.
25
+ *
26
+ * LAPIS filter to select the displayed data.
27
+ */
28
+ @property({ type: Object })
29
+ lapisFilter: Record<string, string | number | null | boolean> = {};
30
+
31
+ /**
32
+ * The type of the sequence for which the mutations should be shown.
33
+ */
34
+ @property({ type: String })
35
+ sequenceType: 'nucleotide' | 'amino acid' = 'nucleotide';
36
+
37
+ /**
38
+ * A list of tabs with views that this component should provide.
39
+ */
40
+ @property({ type: Array })
41
+ views: 'grid'[] = ['grid'];
42
+
43
+ /**
44
+ * The width of the component.
45
+ *
46
+ * Visit https://genspectrum.github.io/dashboard-components/?path=/docs/components-size-of-components--docs for more information.
47
+ */
48
+ @property({ type: String })
49
+ width: string = '100%';
50
+
51
+ /**
52
+ * The height of the component.
53
+ *
54
+ * Visit https://genspectrum.github.io/dashboard-components/?path=/docs/components-size-of-components--docs for more information.
55
+ */
56
+ @property({ type: String })
57
+ height: string = '700px';
58
+
59
+ /**
60
+ * The granularity of the time axis.
61
+ */
62
+ @property({ type: String })
63
+ granularity: 'day' | 'week' | 'month' | 'year' = 'week';
64
+
65
+ /**
66
+ * Required.
67
+ *
68
+ * The LAPIS field that the data should be aggregated by.
69
+ * The values will be used for the columns of the grid.
70
+ * Must be a field of type `date` in LAPIS.
71
+ */
72
+ @property({ type: String })
73
+ lapisDateField: string = 'date';
74
+
75
+ override render() {
76
+ return (
77
+ <MutationsOverTime
78
+ lapisFilter={this.lapisFilter}
79
+ sequenceType={this.sequenceType}
80
+ views={this.views}
81
+ width={this.width}
82
+ height={this.height}
83
+ granularity={this.granularity}
84
+ lapisDateField={this.lapisDateField}
85
+ />
86
+ );
87
+ }
88
+ }
89
+
90
+ declare global {
91
+ interface HTMLElementTagNameMap {
92
+ 'gs-mutations-over-time-component': MutationsOverTimeComponent;
93
+ }
94
+ }
95
+
96
+ /* eslint-disable @typescript-eslint/no-unused-vars, no-unused-vars */
97
+ type LapisFilterMatches = Expect<
98
+ Equals<typeof MutationsOverTimeComponent.prototype.lapisFilter, MutationsOverTimeProps['lapisFilter']>
99
+ >;
100
+ type SequenceTypeMatches = Expect<
101
+ Equals<typeof MutationsOverTimeComponent.prototype.sequenceType, MutationsOverTimeProps['sequenceType']>
102
+ >;
103
+ type ViewsMatches = Expect<Equals<typeof MutationsOverTimeComponent.prototype.views, MutationsOverTimeProps['views']>>;
104
+ type GranularityMatches = Expect<
105
+ Equals<typeof MutationsOverTimeComponent.prototype.granularity, MutationsOverTimeProps['granularity']>
106
+ >;
107
+ /* eslint-enable @typescript-eslint/no-unused-vars, no-unused-vars */
@@ -4,3 +4,4 @@ export { PrevalenceOverTimeComponent } from './gs-prevalence-over-time';
4
4
  export { RelativeGrowthAdvantageComponent } from './gs-relative-growth-advantage';
5
5
  export { AggregateComponent } from './gs-aggregate';
6
6
  export { NumberSequencesOverTimeComponent } from './gs-number-sequences-over-time';
7
+ export { MutationsOverTimeComponent } from './gs-mutations-over-time';