@genspectrum/dashboard-components 0.16.2 → 0.16.4
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/custom-elements.json +72 -7
- package/dist/assets/mutationOverTimeWorker-CPfQDLe6.js.map +1 -0
- package/dist/components.d.ts +60 -21
- package/dist/components.js +804 -608
- package/dist/components.js.map +1 -1
- package/dist/style.css +21 -0
- package/dist/util.d.ts +69 -25
- package/package.json +5 -2
- package/src/preact/MutationAnnotationsContext.spec.tsx +58 -0
- package/src/preact/MutationAnnotationsContext.tsx +72 -0
- package/src/preact/components/annotated-mutation.stories.tsx +164 -0
- package/src/preact/components/annotated-mutation.tsx +84 -0
- package/src/preact/components/error-display.tsx +9 -9
- package/src/preact/components/info.tsx +6 -13
- package/src/preact/components/modal.stories.tsx +7 -19
- package/src/preact/components/modal.tsx +35 -4
- package/src/preact/mutationComparison/mutation-comparison-table.tsx +14 -1
- package/src/preact/mutationComparison/mutation-comparison-venn.tsx +39 -8
- package/src/preact/mutationComparison/mutation-comparison.stories.tsx +36 -12
- package/src/preact/mutationComparison/mutation-comparison.tsx +2 -0
- package/src/preact/mutations/mutations-table.tsx +14 -2
- package/src/preact/mutations/mutations.stories.tsx +33 -1
- package/src/preact/mutations/mutations.tsx +1 -0
- package/src/preact/mutationsOverTime/mutations-over-time-grid.tsx +19 -8
- package/src/preact/mutationsOverTime/mutations-over-time.stories.tsx +29 -5
- package/src/preact/mutationsOverTime/mutations-over-time.tsx +13 -1
- package/src/preact/sequencesByLocation/sequences-by-location-map.tsx +28 -30
- package/src/preact/shared/stories/expectMutationAnnotation.ts +13 -0
- package/src/preact/wastewater/mutationsOverTime/wastewater-mutations-over-time.tsx +6 -1
- package/src/utilEntrypoint.ts +2 -0
- package/src/web-components/gs-app.spec-d.ts +10 -0
- package/src/web-components/gs-app.stories.ts +24 -6
- package/src/web-components/gs-app.ts +17 -0
- package/src/web-components/mutation-annotations-context.ts +16 -0
- package/src/web-components/visualization/gs-mutation-comparison.stories.ts +18 -1
- package/src/web-components/visualization/gs-mutation-comparison.tsx +19 -8
- package/src/web-components/visualization/gs-mutations-over-time.stories.ts +19 -1
- package/src/web-components/visualization/gs-mutations-over-time.tsx +22 -11
- package/src/web-components/visualization/gs-mutations.stories.ts +19 -1
- package/src/web-components/visualization/gs-mutations.tsx +20 -9
- package/src/web-components/wastewaterVisualization/gs-wastewater-mutations-over-time.stories.ts +11 -1
- package/src/web-components/wastewaterVisualization/gs-wastewater-mutations-over-time.tsx +18 -7
- package/standalone-bundle/assets/mutationOverTimeWorker-CERZSdcA.js.map +1 -0
- package/standalone-bundle/dashboard-components.js +12555 -11853
- package/standalone-bundle/dashboard-components.js.map +1 -1
- package/standalone-bundle/style.css +1 -1
- package/dist/assets/mutationOverTimeWorker-BL50C-yi.js.map +0 -1
- package/standalone-bundle/assets/mutationOverTimeWorker-CFB5-Mdk.js.map +0 -1
|
@@ -5,8 +5,10 @@ import { MutationsOverTime, type MutationsOverTimeProps } from './mutations-over
|
|
|
5
5
|
import { LAPIS_URL } from '../../constants';
|
|
6
6
|
import referenceGenome from '../../lapisApi/__mockData__/referenceGenome.json';
|
|
7
7
|
import { LapisUrlContextProvider } from '../LapisUrlContext';
|
|
8
|
+
import { MutationAnnotationsContextProvider } from '../MutationAnnotationsContext';
|
|
8
9
|
import { ReferenceGenomeContext } from '../ReferenceGenomeContext';
|
|
9
10
|
import { expectInvalidAttributesErrorMessage } from '../shared/stories/expectErrorMessage';
|
|
11
|
+
import { expectMutationAnnotation } from '../shared/stories/expectMutationAnnotation';
|
|
10
12
|
|
|
11
13
|
const meta: Meta<MutationsOverTimeProps> = {
|
|
12
14
|
title: 'Visualization/Mutation over time',
|
|
@@ -38,13 +40,32 @@ const meta: Meta<MutationsOverTimeProps> = {
|
|
|
38
40
|
|
|
39
41
|
export default meta;
|
|
40
42
|
|
|
43
|
+
const mutationAnnotations = [
|
|
44
|
+
{
|
|
45
|
+
name: 'I am a mutation annotation!',
|
|
46
|
+
description: 'This describes what is special about these mutations.',
|
|
47
|
+
symbol: '#',
|
|
48
|
+
nucleotideMutations: ['C44T', 'C774T', 'G24872T', 'T23011-'],
|
|
49
|
+
aminoAcidMutations: ['S:501Y', 'S:S31-', 'ORF1a:S4286C'],
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: 'I am another mutation annotation!',
|
|
53
|
+
description: 'This describes what is special about these other mutations.',
|
|
54
|
+
symbol: '+',
|
|
55
|
+
nucleotideMutations: ['C44T', 'A13121T'],
|
|
56
|
+
aminoAcidMutations: ['S:501Y', 'S:S31-', 'ORF1a:S4286C'],
|
|
57
|
+
},
|
|
58
|
+
];
|
|
59
|
+
|
|
41
60
|
export const Default: StoryObj<MutationsOverTimeProps> = {
|
|
42
61
|
render: (args: MutationsOverTimeProps) => (
|
|
43
|
-
<
|
|
44
|
-
<
|
|
45
|
-
<
|
|
46
|
-
|
|
47
|
-
|
|
62
|
+
<MutationAnnotationsContextProvider value={mutationAnnotations}>
|
|
63
|
+
<LapisUrlContextProvider value={LAPIS_URL}>
|
|
64
|
+
<ReferenceGenomeContext.Provider value={referenceGenome}>
|
|
65
|
+
<MutationsOverTime {...args} />
|
|
66
|
+
</ReferenceGenomeContext.Provider>
|
|
67
|
+
</LapisUrlContextProvider>
|
|
68
|
+
</MutationAnnotationsContextProvider>
|
|
48
69
|
),
|
|
49
70
|
args: {
|
|
50
71
|
lapisFilter: { pangoLineage: 'JN.1*', dateFrom: '2024-01-15', dateTo: '2024-07-10' },
|
|
@@ -55,6 +76,9 @@ export const Default: StoryObj<MutationsOverTimeProps> = {
|
|
|
55
76
|
lapisDateField: 'date',
|
|
56
77
|
initialMeanProportionInterval: { min: 0.05, max: 0.9 },
|
|
57
78
|
},
|
|
79
|
+
play: async ({ canvasElement }) => {
|
|
80
|
+
await expectMutationAnnotation(canvasElement, 'C44T');
|
|
81
|
+
},
|
|
58
82
|
};
|
|
59
83
|
|
|
60
84
|
// This test uses mock data: showMessagWhenTooManyMutations.ts (through mutationOverTimeWorker.mock.ts)
|
|
@@ -161,7 +161,13 @@ const MutationsOverTimeTabs: FunctionComponent<MutationOverTimeTabsProps> = ({
|
|
|
161
161
|
case 'grid':
|
|
162
162
|
return {
|
|
163
163
|
title: 'Grid',
|
|
164
|
-
content:
|
|
164
|
+
content: (
|
|
165
|
+
<MutationsOverTimeGrid
|
|
166
|
+
data={filteredData}
|
|
167
|
+
colorScale={colorScale}
|
|
168
|
+
sequenceType={originalComponentProps.sequenceType}
|
|
169
|
+
/>
|
|
170
|
+
),
|
|
165
171
|
};
|
|
166
172
|
}
|
|
167
173
|
};
|
|
@@ -257,6 +263,12 @@ const MutationsOverTimeInfo: FunctionComponent<MutationsOverTimeInfoProps> = ({
|
|
|
257
263
|
organism has multiple segments/genes), and applying a filter based on the proportion of the mutation's
|
|
258
264
|
occurrence over the entire time range.
|
|
259
265
|
</InfoParagraph>
|
|
266
|
+
<InfoParagraph>
|
|
267
|
+
The grid cells have a tooltip that will show more detailed information. It shows the count of samples
|
|
268
|
+
that have the mutation and the count of samples with coverage (i.e. a non-ambiguous read) in this
|
|
269
|
+
timeframe. Ambiguous reads are excluded when calculating the proportion. It also shows the total count
|
|
270
|
+
of samples in this timeframe.
|
|
271
|
+
</InfoParagraph>
|
|
260
272
|
<InfoComponentCode componentName='mutations-over-time' params={originalComponentProps} lapisUrl={lapis} />
|
|
261
273
|
</Info>
|
|
262
274
|
);
|
|
@@ -5,7 +5,7 @@ import { useEffect, useRef } from 'preact/hooks';
|
|
|
5
5
|
|
|
6
6
|
import type { EnhancedGeoJsonFeatureProperties } from '../../query/computeMapLocationData';
|
|
7
7
|
import { InfoHeadline1, InfoParagraph } from '../components/info';
|
|
8
|
-
import { Modal
|
|
8
|
+
import { Modal } from '../components/modal';
|
|
9
9
|
import { AspectRatio } from '../shared/aspectRatio/AspectRatio';
|
|
10
10
|
import { formatProportion } from '../shared/table/formatProportion';
|
|
11
11
|
|
|
@@ -102,39 +102,37 @@ const DataMatchInformation: FunctionComponent<DataMatchInformationProps> = ({
|
|
|
102
102
|
nullCount,
|
|
103
103
|
hasTableView,
|
|
104
104
|
}) => {
|
|
105
|
-
const modalRef = useModalRef();
|
|
106
|
-
|
|
107
105
|
const proportion = formatProportion(countOfMatchedLocationData / totalCount);
|
|
108
106
|
|
|
109
107
|
return (
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
108
|
+
<Modal
|
|
109
|
+
buttonClassName='text-sm absolute bottom-0 px-1 z-[1001] bg-white rounded border'
|
|
110
|
+
modalContent={
|
|
111
|
+
<>
|
|
112
|
+
<InfoHeadline1>Sequences By Location - Map View</InfoHeadline1>
|
|
113
|
+
<InfoParagraph>
|
|
114
|
+
The current filter has matched {totalCount.toLocaleString('en-us')} sequences. From these
|
|
115
|
+
sequences, we were able to match {countOfMatchedLocationData.toLocaleString('en-us')} (
|
|
116
|
+
{proportion}) on locations on the map.
|
|
117
|
+
</InfoParagraph>
|
|
118
|
+
<InfoParagraph>
|
|
119
|
+
{unmatchedLocations.length > 0 && (
|
|
120
|
+
<>
|
|
121
|
+
The following locations from the data could not be matched on the map:{' '}
|
|
122
|
+
{unmatchedLocations.map((it) => `"${it}"`).join(', ')}.{' '}
|
|
123
|
+
</>
|
|
124
|
+
)}
|
|
125
|
+
{nullCount > 0 &&
|
|
126
|
+
`${nullCount.toLocaleString('en-us')} matching sequences have no location information. `}
|
|
127
|
+
{hasTableView && 'You can check the table view for more detailed information.'}
|
|
128
|
+
</InfoParagraph>
|
|
129
|
+
</>
|
|
130
|
+
}
|
|
131
|
+
>
|
|
132
|
+
<p className='tooltip' data-tip='Click for detailed information'>
|
|
116
133
|
This map shows {proportion} of the data.
|
|
117
|
-
</
|
|
118
|
-
|
|
119
|
-
<InfoHeadline1>Sequences By Location - Map View</InfoHeadline1>
|
|
120
|
-
<InfoParagraph>
|
|
121
|
-
The current filter has matched {totalCount.toLocaleString('en-us')} sequences. From these sequences,
|
|
122
|
-
we were able to match {countOfMatchedLocationData.toLocaleString('en-us')} ({proportion}) on
|
|
123
|
-
locations on the map.
|
|
124
|
-
</InfoParagraph>
|
|
125
|
-
<InfoParagraph>
|
|
126
|
-
{unmatchedLocations.length > 0 && (
|
|
127
|
-
<>
|
|
128
|
-
The following locations from the data could not be matched on the map:{' '}
|
|
129
|
-
{unmatchedLocations.map((it) => `"${it}"`).join(', ')}.{' '}
|
|
130
|
-
</>
|
|
131
|
-
)}
|
|
132
|
-
{nullCount > 0 &&
|
|
133
|
-
`${nullCount.toLocaleString('en-us')} matching sequences have no location information. `}
|
|
134
|
-
{hasTableView && 'You can check the table view for more detailed information.'}
|
|
135
|
-
</InfoParagraph>
|
|
136
|
-
</Modal>
|
|
137
|
-
</>
|
|
134
|
+
</p>
|
|
135
|
+
</Modal>
|
|
138
136
|
);
|
|
139
137
|
};
|
|
140
138
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { expect, userEvent, waitFor, within } from '@storybook/test';
|
|
2
|
+
|
|
3
|
+
export async function expectMutationAnnotation(canvasElement: HTMLElement, mutation: string) {
|
|
4
|
+
const canvas = within(canvasElement);
|
|
5
|
+
|
|
6
|
+
await waitFor(async () => {
|
|
7
|
+
const annotatedMutation = canvas.getAllByText(mutation)[0];
|
|
8
|
+
await expect(annotatedMutation).toBeVisible();
|
|
9
|
+
await userEvent.click(annotatedMutation);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
await waitFor(() => expect(canvas.getByText(`Annotations for ${mutation}`)).toBeVisible());
|
|
13
|
+
}
|
|
@@ -102,7 +102,12 @@ const MutationsOverTimeTabs: FunctionComponent<MutationOverTimeTabsProps> = ({
|
|
|
102
102
|
const tabs = mutationOverTimeDataPerLocation.map(({ location, data }) => ({
|
|
103
103
|
title: location,
|
|
104
104
|
content: (
|
|
105
|
-
<MutationsOverTimeGrid
|
|
105
|
+
<MutationsOverTimeGrid
|
|
106
|
+
data={data}
|
|
107
|
+
colorScale={colorScale}
|
|
108
|
+
maxNumberOfGridRows={maxNumberOfGridRows}
|
|
109
|
+
sequenceType={originalComponentProps.sequenceType}
|
|
110
|
+
/>
|
|
106
111
|
),
|
|
107
112
|
}));
|
|
108
113
|
|
package/src/utilEntrypoint.ts
CHANGED
|
@@ -36,3 +36,5 @@ export type { AxisMax, YAxisMaxConfig } from './preact/shared/charts/getYAxisMax
|
|
|
36
36
|
export { LocationChangedEvent } from './preact/locationFilter/LocationChangedEvent';
|
|
37
37
|
export { LineageFilterChangedEvent } from './preact/lineageFilter/LineageFilterChangedEvent';
|
|
38
38
|
export { TextFilterChangedEvent } from './preact/textFilter/TextFilterChangedEvent';
|
|
39
|
+
|
|
40
|
+
export type { MutationAnnotations, MutationAnnotation } from './web-components/mutation-annotations-context';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { describe, expectTypeOf, test } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { AppComponent } from './gs-app';
|
|
4
|
+
import { type MutationAnnotations } from './mutation-annotations-context';
|
|
5
|
+
|
|
6
|
+
describe('gs-app types', () => {
|
|
7
|
+
test('mutationAnnotations type should match', ({}) => {
|
|
8
|
+
expectTypeOf(AppComponent.prototype).toHaveProperty('mutationAnnotations').toEqualTypeOf<MutationAnnotations>();
|
|
9
|
+
});
|
|
10
|
+
});
|
|
@@ -10,6 +10,7 @@ import { lapisContext } from './lapis-context';
|
|
|
10
10
|
import { referenceGenomeContext } from './reference-genome-context';
|
|
11
11
|
import { withComponentDocs } from '../../.storybook/ComponentDocsBlock';
|
|
12
12
|
import { LAPIS_URL, REFERENCE_GENOME_ENDPOINT } from '../constants';
|
|
13
|
+
import { type MutationAnnotations, mutationAnnotationsContext } from './mutation-annotations-context';
|
|
13
14
|
import type { ReferenceGenome } from '../lapisApi/ReferenceGenome';
|
|
14
15
|
import referenceGenome from '../lapisApi/__mockData__/referenceGenome.json';
|
|
15
16
|
|
|
@@ -34,18 +35,29 @@ const meta: Meta = {
|
|
|
34
35
|
|
|
35
36
|
export default meta;
|
|
36
37
|
|
|
37
|
-
|
|
38
|
+
type StoryProps = { lapis: string; mutationAnnotations: MutationAnnotations };
|
|
39
|
+
|
|
40
|
+
const Template: StoryObj<StoryProps> = {
|
|
38
41
|
render: (args) => {
|
|
39
|
-
return html` <gs-app lapis="${args.lapis}">
|
|
42
|
+
return html` <gs-app lapis="${args.lapis}" .mutationAnnotations="${args.mutationAnnotations}">
|
|
40
43
|
<gs-app-display></gs-app-display>
|
|
41
44
|
</gs-app>`;
|
|
42
45
|
},
|
|
43
46
|
args: {
|
|
44
47
|
lapis: LAPIS_URL,
|
|
48
|
+
mutationAnnotations: [
|
|
49
|
+
{
|
|
50
|
+
name: 'I am an annotation!',
|
|
51
|
+
description: 'This describes what is special about these mutations.',
|
|
52
|
+
symbol: '*',
|
|
53
|
+
nucleotideMutations: ['C44T', 'C774T', 'G24872T', 'T23011-'],
|
|
54
|
+
aminoAcidMutations: ['S:501Y', 'S:S31-', 'ORF1a:S4286C'],
|
|
55
|
+
},
|
|
56
|
+
],
|
|
45
57
|
},
|
|
46
58
|
};
|
|
47
59
|
|
|
48
|
-
export const Default: StoryObj<
|
|
60
|
+
export const Default: StoryObj<StoryProps> = {
|
|
49
61
|
...Template,
|
|
50
62
|
play: async ({ canvasElement }) => {
|
|
51
63
|
const canvas = within(canvasElement);
|
|
@@ -53,11 +65,12 @@ export const Default: StoryObj<{ lapis: string }> = {
|
|
|
53
65
|
await waitFor(async () => {
|
|
54
66
|
await expect(canvas.getByText(LAPIS_URL)).toBeVisible();
|
|
55
67
|
await expect(canvas.getByText('"name": "ORF1a",', { exact: false })).toBeVisible();
|
|
68
|
+
await expect(canvas.getByText('I am an annotation!', { exact: false })).toBeVisible();
|
|
56
69
|
});
|
|
57
70
|
},
|
|
58
71
|
};
|
|
59
72
|
|
|
60
|
-
export const WithNoLapisUrl: StoryObj<
|
|
73
|
+
export const WithNoLapisUrl: StoryObj<StoryProps> = {
|
|
61
74
|
...Default,
|
|
62
75
|
args: {
|
|
63
76
|
...Default.args,
|
|
@@ -72,7 +85,7 @@ export const WithNoLapisUrl: StoryObj<{ lapis: string }> = {
|
|
|
72
85
|
},
|
|
73
86
|
};
|
|
74
87
|
|
|
75
|
-
export const DelayFetchingReferenceGenome: StoryObj<
|
|
88
|
+
export const DelayFetchingReferenceGenome: StoryObj<StoryProps> = {
|
|
76
89
|
...Template,
|
|
77
90
|
parameters: {
|
|
78
91
|
fetchMock: {
|
|
@@ -95,7 +108,7 @@ export const DelayFetchingReferenceGenome: StoryObj<{ lapis: string }> = {
|
|
|
95
108
|
},
|
|
96
109
|
};
|
|
97
110
|
|
|
98
|
-
export const FailsToFetchReferenceGenome: StoryObj<
|
|
111
|
+
export const FailsToFetchReferenceGenome: StoryObj<StoryProps> = {
|
|
99
112
|
...Template,
|
|
100
113
|
args: {
|
|
101
114
|
lapis: 'https://url.to.lapis-definitely-not-a-valid-url',
|
|
@@ -121,6 +134,9 @@ class AppDisplay extends LitElement {
|
|
|
121
134
|
genes: [],
|
|
122
135
|
};
|
|
123
136
|
|
|
137
|
+
@consume({ context: mutationAnnotationsContext, subscribe: true })
|
|
138
|
+
mutationAnnotations: MutationAnnotations = [];
|
|
139
|
+
|
|
124
140
|
override render() {
|
|
125
141
|
return html`
|
|
126
142
|
<h1 class="text-xl font-bold">Dummy component</h1>
|
|
@@ -132,6 +148,8 @@ class AppDisplay extends LitElement {
|
|
|
132
148
|
<p>${this.lapis}</p>
|
|
133
149
|
<h2 class="text-lg font-bold">Reference genomes</h2>
|
|
134
150
|
<pre><code>${JSON.stringify(this.referenceGenome, null, 2)}</code></pre>
|
|
151
|
+
<h2 class="text-lg font-bold">Mutation annotations</h2>
|
|
152
|
+
<pre><code>${JSON.stringify(this.mutationAnnotations, null, 2)}</code></pre>
|
|
135
153
|
`;
|
|
136
154
|
}
|
|
137
155
|
|
|
@@ -6,6 +6,7 @@ import type { DetailedHTMLProps, HTMLAttributes } from 'react';
|
|
|
6
6
|
import z from 'zod';
|
|
7
7
|
|
|
8
8
|
import { lapisContext } from './lapis-context';
|
|
9
|
+
import { mutationAnnotationsContext } from './mutation-annotations-context';
|
|
9
10
|
import { referenceGenomeContext } from './reference-genome-context';
|
|
10
11
|
import { type ReferenceGenome } from '../lapisApi/ReferenceGenome';
|
|
11
12
|
import { fetchReferenceGenome } from '../lapisApi/lapisApi';
|
|
@@ -21,6 +22,7 @@ const lapisUrlSchema = z.string().url();
|
|
|
21
22
|
* It makes use of the [Lit Context](https://lit.dev/docs/data/context/) to
|
|
22
23
|
* - provide the URL to the LAPIS instance to all its children
|
|
23
24
|
* - fetch the reference genomes from LAPIS and provide it to all its children
|
|
25
|
+
* - distribute the mutation annotations config to its children
|
|
24
26
|
*
|
|
25
27
|
* This will show an error message if the reference genome cannot be fetched
|
|
26
28
|
* (e.g., due to an invalid LAPIS URL).
|
|
@@ -40,6 +42,21 @@ export class AppComponent extends LitElement {
|
|
|
40
42
|
@property()
|
|
41
43
|
lapis: string = '';
|
|
42
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Supply lists of mutations that are especially relevant for the current organism.
|
|
47
|
+
* Whenever other components display mutations, matching mutations will be highlighted by appending the `symbol`.
|
|
48
|
+
* On hover, a tooltip with the `name` and `description` will be shown.
|
|
49
|
+
*/
|
|
50
|
+
@provide({ context: mutationAnnotationsContext })
|
|
51
|
+
@property({ type: Array })
|
|
52
|
+
mutationAnnotations: {
|
|
53
|
+
name: string;
|
|
54
|
+
description: string;
|
|
55
|
+
symbol: string;
|
|
56
|
+
nucleotideMutations: string[];
|
|
57
|
+
aminoAcidMutations: string[];
|
|
58
|
+
}[] = [];
|
|
59
|
+
|
|
43
60
|
/**
|
|
44
61
|
* @internal
|
|
45
62
|
*/
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createContext } from '@lit/context';
|
|
2
|
+
import z from 'zod';
|
|
3
|
+
|
|
4
|
+
const mutationAnnotationSchema = z.object({
|
|
5
|
+
name: z.string(),
|
|
6
|
+
description: z.string(),
|
|
7
|
+
symbol: z.string(),
|
|
8
|
+
nucleotideMutations: z.array(z.string()),
|
|
9
|
+
aminoAcidMutations: z.array(z.string()),
|
|
10
|
+
});
|
|
11
|
+
export type MutationAnnotation = z.infer<typeof mutationAnnotationSchema>;
|
|
12
|
+
|
|
13
|
+
export const mutationAnnotationsSchema = z.array(mutationAnnotationSchema);
|
|
14
|
+
export type MutationAnnotations = z.infer<typeof mutationAnnotationsSchema>;
|
|
15
|
+
|
|
16
|
+
export const mutationAnnotationsContext = createContext<MutationAnnotations>(Symbol('mutation-annotations-context'));
|
|
@@ -50,9 +50,26 @@ const meta: Meta<Required<MutationComparisonProps>> = {
|
|
|
50
50
|
|
|
51
51
|
export default meta;
|
|
52
52
|
|
|
53
|
+
const mutationAnnotations = [
|
|
54
|
+
{
|
|
55
|
+
name: 'I am a mutation annotation!',
|
|
56
|
+
description: 'This describes what is special about these mutations.',
|
|
57
|
+
symbol: '#',
|
|
58
|
+
nucleotideMutations: ['G199-', 'C3037T'],
|
|
59
|
+
aminoAcidMutations: ['N:G204R'],
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: 'I am another mutation annotation!',
|
|
63
|
+
description: 'This describes what is special about these other mutations.',
|
|
64
|
+
symbol: '+',
|
|
65
|
+
nucleotideMutations: ['C3037T', 'A23403G'],
|
|
66
|
+
aminoAcidMutations: ['ORF1a:I2230T'],
|
|
67
|
+
},
|
|
68
|
+
];
|
|
69
|
+
|
|
53
70
|
const Template: StoryObj<Required<MutationComparisonProps>> = {
|
|
54
71
|
render: (args) => html`
|
|
55
|
-
<gs-app lapis="${LAPIS_URL}">
|
|
72
|
+
<gs-app lapis="${LAPIS_URL}" .mutationAnnotations=${mutationAnnotations}>
|
|
56
73
|
<gs-mutation-comparison
|
|
57
74
|
.lapisFilters=${args.lapisFilters}
|
|
58
75
|
.sequenceType=${args.sequenceType}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import { consume } from '@lit/context';
|
|
1
2
|
import { customElement, property } from 'lit/decorators.js';
|
|
2
3
|
import type { DetailedHTMLProps, HTMLAttributes } from 'react';
|
|
3
4
|
|
|
5
|
+
import { MutationAnnotationsContextProvider } from '../../preact/MutationAnnotationsContext';
|
|
4
6
|
import { MutationComparison, type MutationComparisonProps } from '../../preact/mutationComparison/mutation-comparison';
|
|
5
7
|
import { type Equals, type Expect } from '../../utils/typeAssertions';
|
|
6
8
|
import { PreactLitAdapterWithGridJsStyles } from '../PreactLitAdapterWithGridJsStyles';
|
|
9
|
+
import { type MutationAnnotations, mutationAnnotationsContext } from '../mutation-annotations-context';
|
|
7
10
|
|
|
8
11
|
/**
|
|
9
12
|
* ## Context
|
|
@@ -88,16 +91,24 @@ export class MutationComparisonComponent extends PreactLitAdapterWithGridJsStyle
|
|
|
88
91
|
@property({ type: Object })
|
|
89
92
|
pageSize: boolean | number = false;
|
|
90
93
|
|
|
94
|
+
/**
|
|
95
|
+
* @internal
|
|
96
|
+
*/
|
|
97
|
+
@consume({ context: mutationAnnotationsContext, subscribe: true })
|
|
98
|
+
mutationAnnotations: MutationAnnotations = [];
|
|
99
|
+
|
|
91
100
|
override render() {
|
|
92
101
|
return (
|
|
93
|
-
<
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
102
|
+
<MutationAnnotationsContextProvider value={this.mutationAnnotations}>
|
|
103
|
+
<MutationComparison
|
|
104
|
+
lapisFilters={this.lapisFilters}
|
|
105
|
+
sequenceType={this.sequenceType}
|
|
106
|
+
views={this.views}
|
|
107
|
+
width={this.width}
|
|
108
|
+
height={this.height}
|
|
109
|
+
pageSize={this.pageSize}
|
|
110
|
+
/>
|
|
111
|
+
</MutationAnnotationsContextProvider>
|
|
101
112
|
);
|
|
102
113
|
}
|
|
103
114
|
}
|
|
@@ -64,9 +64,27 @@ const meta: Meta<Required<MutationsOverTimeProps>> = {
|
|
|
64
64
|
|
|
65
65
|
export default meta;
|
|
66
66
|
|
|
67
|
+
const mutationAnnotations = [
|
|
68
|
+
{
|
|
69
|
+
name: 'I am a mutation annotation!',
|
|
70
|
+
description:
|
|
71
|
+
'This describes what is special about these mutations. <a class="link" href="/">And it has a link.</a>',
|
|
72
|
+
symbol: '#',
|
|
73
|
+
nucleotideMutations: ['C44T', 'C774T', 'G24872T', 'T23011-'],
|
|
74
|
+
aminoAcidMutations: ['S:501Y', 'S:S31-', 'ORF1a:S4286C'],
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: 'I am another mutation annotation!',
|
|
78
|
+
description: 'This describes what is special about these other mutations.',
|
|
79
|
+
symbol: '+',
|
|
80
|
+
nucleotideMutations: ['C44T', 'A13121T'],
|
|
81
|
+
aminoAcidMutations: ['S:501Y', 'S:S31-', 'ORF1a:S4286C'],
|
|
82
|
+
},
|
|
83
|
+
];
|
|
84
|
+
|
|
67
85
|
const Template: StoryObj<Required<MutationsOverTimeProps>> = {
|
|
68
86
|
render: (args) => html`
|
|
69
|
-
<gs-app lapis="${LAPIS_URL}">
|
|
87
|
+
<gs-app lapis="${LAPIS_URL}" .mutationAnnotations=${mutationAnnotations}>
|
|
70
88
|
<gs-mutations-over-time
|
|
71
89
|
.lapisFilter=${args.lapisFilter}
|
|
72
90
|
.sequenceType=${args.sequenceType}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import { consume } from '@lit/context';
|
|
1
2
|
import { customElement, property } from 'lit/decorators.js';
|
|
2
3
|
import type { DetailedHTMLProps, HTMLAttributes } from 'react';
|
|
3
4
|
|
|
5
|
+
import { MutationAnnotationsContextProvider } from '../../preact/MutationAnnotationsContext';
|
|
4
6
|
import { MutationsOverTime, type MutationsOverTimeProps } from '../../preact/mutationsOverTime/mutations-over-time';
|
|
5
7
|
import type { Equals, Expect } from '../../utils/typeAssertions';
|
|
6
8
|
import { PreactLitAdapterWithGridJsStyles } from '../PreactLitAdapterWithGridJsStyles';
|
|
9
|
+
import { type MutationAnnotations, mutationAnnotationsContext } from '../mutation-annotations-context';
|
|
7
10
|
|
|
8
11
|
/**
|
|
9
12
|
* ## Context
|
|
@@ -105,19 +108,27 @@ export class MutationsOverTimeComponent extends PreactLitAdapterWithGridJsStyles
|
|
|
105
108
|
@property({ type: Object })
|
|
106
109
|
initialMeanProportionInterval: { min: number; max: number } = { min: 0.05, max: 0.9 };
|
|
107
110
|
|
|
111
|
+
/**
|
|
112
|
+
* @internal
|
|
113
|
+
*/
|
|
114
|
+
@consume({ context: mutationAnnotationsContext, subscribe: true })
|
|
115
|
+
mutationAnnotations: MutationAnnotations = [];
|
|
116
|
+
|
|
108
117
|
override render() {
|
|
109
118
|
return (
|
|
110
|
-
<
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
119
|
+
<MutationAnnotationsContextProvider value={this.mutationAnnotations}>
|
|
120
|
+
<MutationsOverTime
|
|
121
|
+
lapisFilter={this.lapisFilter}
|
|
122
|
+
sequenceType={this.sequenceType}
|
|
123
|
+
views={this.views}
|
|
124
|
+
width={this.width}
|
|
125
|
+
height={this.height}
|
|
126
|
+
granularity={this.granularity}
|
|
127
|
+
lapisDateField={this.lapisDateField}
|
|
128
|
+
displayMutations={this.displayMutations}
|
|
129
|
+
initialMeanProportionInterval={this.initialMeanProportionInterval}
|
|
130
|
+
/>
|
|
131
|
+
</MutationAnnotationsContextProvider>
|
|
121
132
|
);
|
|
122
133
|
}
|
|
123
134
|
}
|
|
@@ -68,9 +68,27 @@ const meta: Meta<Required<MutationsProps>> = {
|
|
|
68
68
|
|
|
69
69
|
export default meta;
|
|
70
70
|
|
|
71
|
+
const mutationAnnotations = [
|
|
72
|
+
{
|
|
73
|
+
name: 'I am a mutation annotation!',
|
|
74
|
+
description:
|
|
75
|
+
'This describes what is special about these mutations. <a class="link" href="/">And it has a link.</a>',
|
|
76
|
+
symbol: '#',
|
|
77
|
+
nucleotideMutations: ['C241T', 'C3037T'],
|
|
78
|
+
aminoAcidMutations: ['S:501Y', 'S:S31-', 'ORF1a:S4286C'],
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: 'I am another mutation annotation!',
|
|
82
|
+
description: 'This describes what is special about these other mutations.',
|
|
83
|
+
symbol: '+',
|
|
84
|
+
nucleotideMutations: ['C3037T', 'C11750T'],
|
|
85
|
+
aminoAcidMutations: ['S:501Y', 'S:S31-', 'ORF1a:S4286C'],
|
|
86
|
+
},
|
|
87
|
+
];
|
|
88
|
+
|
|
71
89
|
const Template: StoryObj<Required<MutationsProps>> = {
|
|
72
90
|
render: (args) => html`
|
|
73
|
-
<gs-app lapis="${LAPIS_URL}">
|
|
91
|
+
<gs-app lapis="${LAPIS_URL}" .mutationAnnotations=${mutationAnnotations}>
|
|
74
92
|
<gs-mutations
|
|
75
93
|
.lapisFilter=${args.lapisFilter}
|
|
76
94
|
.baselineLapisFilter=${args.baselineLapisFilter}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import { consume } from '@lit/context';
|
|
1
2
|
import { customElement, property } from 'lit/decorators.js';
|
|
2
3
|
import type { DetailedHTMLProps, HTMLAttributes } from 'react';
|
|
3
4
|
|
|
5
|
+
import { MutationAnnotationsContextProvider } from '../../preact/MutationAnnotationsContext';
|
|
4
6
|
import { Mutations, type MutationsProps } from '../../preact/mutations/mutations';
|
|
5
7
|
import type { Equals, Expect } from '../../utils/typeAssertions';
|
|
6
8
|
import { PreactLitAdapterWithGridJsStyles } from '../PreactLitAdapterWithGridJsStyles';
|
|
9
|
+
import { type MutationAnnotations, mutationAnnotationsContext } from '../mutation-annotations-context';
|
|
7
10
|
|
|
8
11
|
/**
|
|
9
12
|
* ## Context
|
|
@@ -120,17 +123,25 @@ export class MutationsComponent extends PreactLitAdapterWithGridJsStyles {
|
|
|
120
123
|
@property({ type: Object })
|
|
121
124
|
pageSize: boolean | number = false;
|
|
122
125
|
|
|
126
|
+
/**
|
|
127
|
+
* @internal
|
|
128
|
+
*/
|
|
129
|
+
@consume({ context: mutationAnnotationsContext, subscribe: true })
|
|
130
|
+
mutationAnnotations: MutationAnnotations = [];
|
|
131
|
+
|
|
123
132
|
override render() {
|
|
124
133
|
return (
|
|
125
|
-
<
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
+
<MutationAnnotationsContextProvider value={this.mutationAnnotations}>
|
|
135
|
+
<Mutations
|
|
136
|
+
lapisFilter={this.lapisFilter}
|
|
137
|
+
sequenceType={this.sequenceType}
|
|
138
|
+
views={this.views}
|
|
139
|
+
width={this.width}
|
|
140
|
+
height={this.height}
|
|
141
|
+
pageSize={this.pageSize}
|
|
142
|
+
baselineLapisFilter={this.baselineLapisFilter}
|
|
143
|
+
/>
|
|
144
|
+
</MutationAnnotationsContextProvider>
|
|
134
145
|
);
|
|
135
146
|
}
|
|
136
147
|
}
|
package/src/web-components/wastewaterVisualization/gs-wastewater-mutations-over-time.stories.ts
CHANGED
|
@@ -52,9 +52,19 @@ const meta: Meta<WastewaterMutationsOverTimeProps & { infoText: string }> = {
|
|
|
52
52
|
|
|
53
53
|
export default meta;
|
|
54
54
|
|
|
55
|
+
const mutationAnnotations = [
|
|
56
|
+
{
|
|
57
|
+
name: 'I am an annotation!',
|
|
58
|
+
description: 'This describes what is special about these mutations.',
|
|
59
|
+
symbol: '*',
|
|
60
|
+
nucleotideMutations: ['C3422A', 'G6661A', 'G7731A'],
|
|
61
|
+
aminoAcidMutations: ['S:501Y', 'S:S31-', 'ORF1a:S4286C'],
|
|
62
|
+
},
|
|
63
|
+
];
|
|
64
|
+
|
|
55
65
|
export const WastewaterMutationsOverTime: StoryObj<WastewaterMutationsOverTimeProps & { infoText: string }> = {
|
|
56
66
|
render: (args) => html`
|
|
57
|
-
<gs-app lapis="${WISE_LAPIS_URL}">
|
|
67
|
+
<gs-app lapis="${WISE_LAPIS_URL}" .mutationAnnotations=${mutationAnnotations}>
|
|
58
68
|
<gs-wastewater-mutations-over-time
|
|
59
69
|
.lapisFilter=${args.lapisFilter}
|
|
60
70
|
.sequenceType=${args.sequenceType}
|