@genspectrum/dashboard-components 0.18.2 → 0.18.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.
- package/custom-elements.json +2 -2
- package/dist/assets/{mutationOverTimeWorker-ChQTFL68.js.map → mutationOverTimeWorker--b8ZHlji.js.map} +1 -1
- package/dist/components.d.ts +16 -287
- package/dist/components.js +114 -39
- package/dist/components.js.map +1 -1
- package/dist/style.css +2 -2
- package/dist/util.d.ts +24 -291
- package/package.json +3 -3
- package/src/preact/MutationAnnotationsContext.spec.tsx +103 -34
- package/src/preact/MutationAnnotationsContext.tsx +49 -7
- package/src/preact/components/annotated-mutation.stories.tsx +0 -5
- package/src/preact/components/annotated-mutation.tsx +6 -2
- package/src/preact/mutationComparison/mutation-comparison.stories.tsx +3 -1
- package/src/preact/mutations/mutations.stories.tsx +4 -1
- package/src/preact/mutationsOverTime/mutations-over-time.stories.tsx +3 -1
- package/src/preact/sequencesByLocation/leafletStyleModifications.css +5 -0
- package/src/preact/wastewater/mutationsOverTime/wastewater-mutations-over-time.stories.tsx +25 -0
- package/src/preact/wastewater/mutationsOverTime/wastewater-mutations-over-time.tsx +65 -13
- package/src/web-components/MutationAnnotations.mdx +8 -0
- package/src/web-components/gs-app.stories.ts +2 -0
- package/src/web-components/gs-app.ts +4 -2
- package/src/web-components/mutation-annotations-context.ts +6 -2
- package/standalone-bundle/assets/mutationOverTimeWorker-jChgWnwp.js.map +1 -1
- package/standalone-bundle/dashboard-components.js +5699 -5643
- package/standalone-bundle/dashboard-components.js.map +1 -1
- package/standalone-bundle/style.css +1 -1
|
@@ -6,6 +6,7 @@ import nucleotideMutationsSomeDataset from './__mockData__/nucleotideMutationsSo
|
|
|
6
6
|
import { MutationComparison, type MutationComparisonProps } from './mutation-comparison';
|
|
7
7
|
import { LAPIS_URL, NUCLEOTIDE_MUTATIONS_ENDPOINT } from '../../constants';
|
|
8
8
|
import referenceGenome from '../../lapisApi/__mockData__/referenceGenome.json';
|
|
9
|
+
import { type MutationAnnotations } from '../../web-components/mutation-annotations-context';
|
|
9
10
|
import { LapisUrlContextProvider } from '../LapisUrlContext';
|
|
10
11
|
import { MutationAnnotationsContextProvider } from '../MutationAnnotationsContext';
|
|
11
12
|
import { ReferenceGenomeContext } from '../ReferenceGenomeContext';
|
|
@@ -90,8 +91,9 @@ const mutationAnnotations = [
|
|
|
90
91
|
symbol: '+',
|
|
91
92
|
nucleotideMutations: ['C3037T', 'A23403G'],
|
|
92
93
|
aminoAcidMutations: ['ORF1a:I2230T'],
|
|
94
|
+
aminoAcidPositions: ['ORF1a:3675'],
|
|
93
95
|
},
|
|
94
|
-
];
|
|
96
|
+
] satisfies MutationAnnotations;
|
|
95
97
|
|
|
96
98
|
const Template: StoryObj<MutationComparisonProps> = {
|
|
97
99
|
render: (args) => (
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
import referenceGenome from '../../lapisApi/__mockData__/referenceGenome.json';
|
|
14
14
|
import baselineNucleotideMutations from '../../preact/mutations/__mockData__/baselineNucleotideMutations.json';
|
|
15
15
|
import overallVariantCount from '../../preact/mutations/__mockData__/overallVariantCount.json';
|
|
16
|
+
import { type MutationAnnotations } from '../../web-components/mutation-annotations-context';
|
|
16
17
|
import { LapisUrlContextProvider } from '../LapisUrlContext';
|
|
17
18
|
import { MutationAnnotationsContextProvider } from '../MutationAnnotationsContext';
|
|
18
19
|
import { ReferenceGenomeContext } from '../ReferenceGenomeContext';
|
|
@@ -45,6 +46,7 @@ const mutationAnnotations = [
|
|
|
45
46
|
description: 'This describes what is special about these mutations.',
|
|
46
47
|
symbol: '#',
|
|
47
48
|
nucleotideMutations: ['C241T', 'C3037T'],
|
|
49
|
+
nucleotidePositions: [],
|
|
48
50
|
aminoAcidMutations: ['N:G204R', 'N:S235F'],
|
|
49
51
|
},
|
|
50
52
|
{
|
|
@@ -52,9 +54,10 @@ const mutationAnnotations = [
|
|
|
52
54
|
description: 'This describes what is special about these other mutations.',
|
|
53
55
|
symbol: '+',
|
|
54
56
|
nucleotideMutations: ['C3037T', 'C11750T'],
|
|
57
|
+
nucleotidePositions: ['14408'],
|
|
55
58
|
aminoAcidMutations: ['ORF1a:S2255F'],
|
|
56
59
|
},
|
|
57
|
-
];
|
|
60
|
+
] satisfies MutationAnnotations;
|
|
58
61
|
|
|
59
62
|
const Template = {
|
|
60
63
|
render: (args: MutationsProps) => (
|
|
@@ -5,6 +5,7 @@ import { type Canvas } from '@storybook/types';
|
|
|
5
5
|
import { MutationsOverTime, type MutationsOverTimeProps } from './mutations-over-time';
|
|
6
6
|
import { LAPIS_URL } from '../../constants';
|
|
7
7
|
import referenceGenome from '../../lapisApi/__mockData__/referenceGenome.json';
|
|
8
|
+
import { type MutationAnnotations } from '../../web-components/mutation-annotations-context';
|
|
8
9
|
import { LapisUrlContextProvider } from '../LapisUrlContext';
|
|
9
10
|
import { MutationAnnotationsContextProvider } from '../MutationAnnotationsContext';
|
|
10
11
|
import { ReferenceGenomeContext } from '../ReferenceGenomeContext';
|
|
@@ -49,6 +50,7 @@ const mutationAnnotations = [
|
|
|
49
50
|
symbol: '#',
|
|
50
51
|
nucleotideMutations: ['C44T', 'C774T', 'G24872T', 'T23011-'],
|
|
51
52
|
aminoAcidMutations: ['S:501Y', 'S:S31-', 'ORF1a:S4286C'],
|
|
53
|
+
nucleotidePositions: ['17334'],
|
|
52
54
|
},
|
|
53
55
|
{
|
|
54
56
|
name: 'I am another mutation annotation!',
|
|
@@ -57,7 +59,7 @@ const mutationAnnotations = [
|
|
|
57
59
|
nucleotideMutations: ['C44T', 'A13121T'],
|
|
58
60
|
aminoAcidMutations: ['S:501Y', 'S:S31-', 'ORF1a:S4286C'],
|
|
59
61
|
},
|
|
60
|
-
];
|
|
62
|
+
] satisfies MutationAnnotations;
|
|
61
63
|
|
|
62
64
|
export const Default: StoryObj<MutationsOverTimeProps> = {
|
|
63
65
|
render: (args: MutationsOverTimeProps) => (
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type Meta, type StoryObj } from '@storybook/preact';
|
|
2
|
+
import { expect } from '@storybook/test';
|
|
2
3
|
|
|
3
4
|
import { WastewaterMutationsOverTime, type WastewaterMutationsOverTimeProps } from './wastewater-mutations-over-time';
|
|
4
5
|
import { WISE_DETAILS_ENDPOINT, WISE_LAPIS_URL } from '../../../constants';
|
|
@@ -65,3 +66,27 @@ export const Default: StoryObj<WastewaterMutationsOverTimeProps> = {
|
|
|
65
66
|
},
|
|
66
67
|
},
|
|
67
68
|
};
|
|
69
|
+
|
|
70
|
+
export const AminoAcids: StoryObj<WastewaterMutationsOverTimeProps> = {
|
|
71
|
+
...Default,
|
|
72
|
+
args: {
|
|
73
|
+
...Default.args,
|
|
74
|
+
sequenceType: 'amino acid',
|
|
75
|
+
},
|
|
76
|
+
play: async ({ canvas, step }) => {
|
|
77
|
+
await step('Wait for component to render', async () => {
|
|
78
|
+
await canvas.findByText('All segments');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
await step("Click 'All segments' button", async () => {
|
|
82
|
+
canvas.getByRole('button', { name: 'All segments' }).click();
|
|
83
|
+
await expect(canvas.getByText('Select none')).toBeInTheDocument();
|
|
84
|
+
canvas.getByRole('button', { name: 'Select none' }).click();
|
|
85
|
+
await canvas.findAllByText('No data available for your filters.');
|
|
86
|
+
canvas.getByRole('checkbox', { name: 'S' }).click();
|
|
87
|
+
await canvas.findAllByText('S:Q493E');
|
|
88
|
+
const element = canvas.queryByText(/ORF1a:/);
|
|
89
|
+
await expect(element).not.toBeInTheDocument();
|
|
90
|
+
});
|
|
91
|
+
},
|
|
92
|
+
};
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { type FunctionComponent } from 'preact';
|
|
2
|
-
import { type Dispatch, type StateUpdater, useState } from 'preact/hooks';
|
|
2
|
+
import { type Dispatch, type StateUpdater, useMemo, useState } from 'preact/hooks';
|
|
3
3
|
import z from 'zod';
|
|
4
4
|
|
|
5
5
|
import { computeWastewaterMutationsOverTimeDataPerLocation } from './computeWastewaterMutationsOverTimeDataPerLocation';
|
|
6
6
|
import { lapisFilterSchema, sequenceTypeSchema } from '../../../types';
|
|
7
|
+
import { Map2dView } from '../../../utils/map2d';
|
|
7
8
|
import { useLapisUrl } from '../../LapisUrlContext';
|
|
8
9
|
import { type ColorScale } from '../../components/color-scale-selector';
|
|
9
10
|
import { ColorScaleSelectorDropdown } from '../../components/color-scale-selector-dropdown';
|
|
@@ -13,6 +14,7 @@ import Info, { InfoComponentCode, InfoHeadline1, InfoParagraph } from '../../com
|
|
|
13
14
|
import { LoadingDisplay } from '../../components/loading-display';
|
|
14
15
|
import { NoDataDisplay } from '../../components/no-data-display';
|
|
15
16
|
import { ResizeContainer } from '../../components/resize-container';
|
|
17
|
+
import { type DisplayedSegment, SegmentSelector } from '../../components/segment-selector';
|
|
16
18
|
import Tabs from '../../components/tabs';
|
|
17
19
|
import { type MutationOverTimeDataMap } from '../../mutationsOverTime/MutationOverTimeData';
|
|
18
20
|
import MutationsOverTimeGrid from '../../mutationsOverTime/mutations-over-time-grid';
|
|
@@ -86,28 +88,67 @@ type MutationOverTimeDataPerLocation = {
|
|
|
86
88
|
data: MutationOverTimeDataMap;
|
|
87
89
|
}[];
|
|
88
90
|
|
|
91
|
+
function useDisplayedSegments(mutations: MutationOverTimeDataPerLocation) {
|
|
92
|
+
const displayedSegments = useMemo(() => {
|
|
93
|
+
const unique = [
|
|
94
|
+
...new Set(
|
|
95
|
+
mutations.flatMap(({ data }) => data.getFirstAxisKeys().map((mutation) => mutation.segment || '')),
|
|
96
|
+
),
|
|
97
|
+
];
|
|
98
|
+
|
|
99
|
+
return unique.map((segment) => ({ segment, label: segment, checked: true }));
|
|
100
|
+
}, [mutations]);
|
|
101
|
+
|
|
102
|
+
return useState<DisplayedSegment[]>(displayedSegments);
|
|
103
|
+
}
|
|
104
|
+
|
|
89
105
|
type MutationOverTimeTabsProps = {
|
|
90
106
|
mutationOverTimeDataPerLocation: MutationOverTimeDataPerLocation;
|
|
91
107
|
originalComponentProps: WastewaterMutationsOverTimeProps;
|
|
92
108
|
};
|
|
93
109
|
|
|
110
|
+
function getFilteredMutationOverTimeData({
|
|
111
|
+
data,
|
|
112
|
+
displayedSegments,
|
|
113
|
+
}: {
|
|
114
|
+
data: MutationOverTimeDataMap;
|
|
115
|
+
displayedSegments: DisplayedSegment[];
|
|
116
|
+
}): MutationOverTimeDataMap {
|
|
117
|
+
const filteredData = new Map2dView(data);
|
|
118
|
+
|
|
119
|
+
const mutationsToFilterOut = data.getFirstAxisKeys().filter((entry) => {
|
|
120
|
+
return displayedSegments.some((segment) => segment.segment === entry.segment && !segment.checked);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
mutationsToFilterOut.forEach((entry) => {
|
|
124
|
+
filteredData.deleteRow(entry);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
return filteredData;
|
|
128
|
+
}
|
|
129
|
+
|
|
94
130
|
const MutationsOverTimeTabs: FunctionComponent<MutationOverTimeTabsProps> = ({
|
|
95
131
|
mutationOverTimeDataPerLocation,
|
|
96
132
|
originalComponentProps,
|
|
97
133
|
}) => {
|
|
98
134
|
const [colorScale, setColorScale] = useState<ColorScale>({ min: 0, max: 1, color: 'indigo' });
|
|
135
|
+
const [displayedSegments, setDisplayedSegments] = useDisplayedSegments(mutationOverTimeDataPerLocation);
|
|
99
136
|
|
|
100
|
-
const tabs =
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
137
|
+
const tabs = useMemo(
|
|
138
|
+
() =>
|
|
139
|
+
mutationOverTimeDataPerLocation.map(({ location, data }) => ({
|
|
140
|
+
title: location,
|
|
141
|
+
content: (
|
|
142
|
+
<MutationsOverTimeGrid
|
|
143
|
+
data={getFilteredMutationOverTimeData({ data, displayedSegments })}
|
|
144
|
+
colorScale={colorScale}
|
|
145
|
+
pageSizes={originalComponentProps.pageSizes}
|
|
146
|
+
sequenceType={originalComponentProps.sequenceType}
|
|
147
|
+
/>
|
|
148
|
+
),
|
|
149
|
+
})),
|
|
150
|
+
[mutationOverTimeDataPerLocation, displayedSegments, colorScale, originalComponentProps],
|
|
151
|
+
);
|
|
111
152
|
|
|
112
153
|
const toolbar = (
|
|
113
154
|
<Toolbar
|
|
@@ -115,6 +156,8 @@ const MutationsOverTimeTabs: FunctionComponent<MutationOverTimeTabsProps> = ({
|
|
|
115
156
|
setColorScale={setColorScale}
|
|
116
157
|
originalComponentProps={originalComponentProps}
|
|
117
158
|
data={mutationOverTimeDataPerLocation}
|
|
159
|
+
displayedSegments={displayedSegments}
|
|
160
|
+
setDisplayedSegments={setDisplayedSegments}
|
|
118
161
|
/>
|
|
119
162
|
);
|
|
120
163
|
|
|
@@ -126,12 +169,21 @@ type ToolbarProps = {
|
|
|
126
169
|
setColorScale: Dispatch<StateUpdater<ColorScale>>;
|
|
127
170
|
originalComponentProps: WastewaterMutationsOverTimeProps;
|
|
128
171
|
data: MutationOverTimeDataPerLocation;
|
|
172
|
+
displayedSegments: DisplayedSegment[];
|
|
173
|
+
setDisplayedSegments: (segments: DisplayedSegment[]) => void;
|
|
129
174
|
};
|
|
130
175
|
|
|
131
|
-
const Toolbar: FunctionComponent<ToolbarProps> = ({
|
|
176
|
+
const Toolbar: FunctionComponent<ToolbarProps> = ({
|
|
177
|
+
colorScale,
|
|
178
|
+
setColorScale,
|
|
179
|
+
originalComponentProps,
|
|
180
|
+
displayedSegments,
|
|
181
|
+
setDisplayedSegments,
|
|
182
|
+
}) => {
|
|
132
183
|
return (
|
|
133
184
|
<>
|
|
134
185
|
<ColorScaleSelectorDropdown colorScale={colorScale} setColorScale={setColorScale} />
|
|
186
|
+
<SegmentSelector displayedSegments={displayedSegments} setDisplayedSegments={setDisplayedSegments} />
|
|
135
187
|
<WastewaterMutationsOverTimeInfo originalComponentProps={originalComponentProps} />
|
|
136
188
|
<Fullscreen />
|
|
137
189
|
</>
|
|
@@ -19,7 +19,9 @@ The mutation annotations can be (optionally) supplied to `gs-app` as a JSON obje
|
|
|
19
19
|
description: 'This describes what is special about these mutations.',
|
|
20
20
|
symbol: '+',
|
|
21
21
|
nucleotideMutations: ['C44T', 'C774T', 'G24872T', 'T23011-'],
|
|
22
|
+
nucleotidePositions: ['123', '234'],
|
|
22
23
|
aminoAcidMutations: ['S:501Y', 'S:S31-', 'ORF1a:S4286C'],
|
|
24
|
+
aminoAcidPositions: ['S:123', 'ORF1a:234']
|
|
23
25
|
},
|
|
24
26
|
]"
|
|
25
27
|
>
|
|
@@ -31,3 +33,9 @@ The mutation annotations are then distributed to child components.
|
|
|
31
33
|
Whenever we display a mutation (e.g. in the `gs-mutations` table view)
|
|
32
34
|
we will append the `symbol` of all matching annotations: <span>C44T<sup class='text-red-600'>+</sup></span>.
|
|
33
35
|
Users can click on the mutation to open a modal that shows the `name` and `description` of the annotation.
|
|
36
|
+
|
|
37
|
+
The annotation can be applied to specific mutations:
|
|
38
|
+
|
|
39
|
+
- `nucleotideMutations: [C44T]` matches only the nucleotide mutation `C44T`,
|
|
40
|
+
- `aminoAcidPositions: [S:123]` matches all amino acid mutations that occur on the gene `S` at position `123`
|
|
41
|
+
- If the pathogen has only one segment, one can omit the segment, writing `123` for any mutation at position `123`.
|
|
@@ -51,7 +51,9 @@ const Template: StoryObj<StoryProps> = {
|
|
|
51
51
|
description: 'This describes what is special about these mutations.',
|
|
52
52
|
symbol: '*',
|
|
53
53
|
nucleotideMutations: ['C44T', 'C774T', 'G24872T', 'T23011-'],
|
|
54
|
+
nucleotidePositions: ['123', '456'],
|
|
54
55
|
aminoAcidMutations: ['S:501Y', 'S:S31-', 'ORF1a:S4286C'],
|
|
56
|
+
aminoAcidPositions: ['S:123'],
|
|
55
57
|
},
|
|
56
58
|
],
|
|
57
59
|
},
|
|
@@ -53,8 +53,10 @@ export class AppComponent extends LitElement {
|
|
|
53
53
|
name: string;
|
|
54
54
|
description: string;
|
|
55
55
|
symbol: string;
|
|
56
|
-
nucleotideMutations
|
|
57
|
-
|
|
56
|
+
nucleotideMutations?: string[];
|
|
57
|
+
nucleotidePositions?: string[];
|
|
58
|
+
aminoAcidMutations?: string[];
|
|
59
|
+
aminoAcidPositions?: string[];
|
|
58
60
|
}[] = [];
|
|
59
61
|
|
|
60
62
|
/**
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { createContext } from '@lit/context';
|
|
2
2
|
import z from 'zod';
|
|
3
3
|
|
|
4
|
+
const annotations = z.array(z.string());
|
|
5
|
+
|
|
4
6
|
const mutationAnnotationSchema = z.object({
|
|
5
7
|
name: z.string(),
|
|
6
8
|
description: z.string(),
|
|
7
9
|
symbol: z.string(),
|
|
8
|
-
nucleotideMutations:
|
|
9
|
-
|
|
10
|
+
nucleotideMutations: annotations.optional(),
|
|
11
|
+
nucleotidePositions: annotations.optional(),
|
|
12
|
+
aminoAcidMutations: annotations.optional(),
|
|
13
|
+
aminoAcidPositions: annotations.optional(),
|
|
10
14
|
});
|
|
11
15
|
export type MutationAnnotation = z.infer<typeof mutationAnnotationSchema>;
|
|
12
16
|
|